How To: Concatenate files using MSBuild tasks
This came across the internal MSBuild discussion alias this week:
How can I concatenate a bunch of individual files into a single file during my build process? It looks like the ReadLinesFromFile and WriteLinesToFile tasks will do what I want, but I can't figure out what kind of batching operators to use.
Dan provided an elegant answer. The first step is to create an ItemGroup with the files you want to concatenate:
<ItemGroup> <InFiles Include="1.in;2.in"/></ItemGroup>
Then create a target to do the concatenation:
<Target Name="ConcatenateFiles"> <ReadLinesFromFile File="%(InFiles.Identity)"> <Output TaskParameter="Lines" ItemName="lines"/> </ReadLinesFromFile> <WriteLinesToFile File="test.out" Lines="@(Lines)" Overwrite="false" /></Target>
The first task, ReadLinesFromFiles, goes through each file in the InFiles list and adds their lines to a new list called Lines. To ensure that each file is done in a loop (batched), the .Identity item metadata is tacked on. The lines that are read in are added to a new property called Lines, which is created by using the Output element. Then WriteLinesToFile takes the generated list and spits them out to a file.
Pretty nifty!
[ Author: Neil Enns ]
Comments
Anonymous
September 29, 2005
Maybe I'm old-fashioned, but I can't help but think that the old:
cat a b c > d
is more elegant and easier to understand. It can easily be extended further, using bash script, easily inserted in a Makefile:
cat $(find -iname *.cs | sort) > d
This modern obsession with XML is fine for things that are wrapped up in a UI, but for something that needs programmer thought, you need (at some level) a programming language.Anonymous
September 29, 2005
That's a fair point. We've actually often wished we had some sort of more straight forward programmability in MSBuild, directly embedded in the project file, for this kind of thing.
There are other ways of achieving the above. As you mention, cat works, and you can involve it by from the <Exec> task.
Another option, if you do this often, would be to write a task called <Cocnatenate> that takes the list of files and the output file name. It would certainly look nicer in the XML!
The ReadLinesFromFiles and WriteLinesToFile tasks were never meant to be used this way, but I thought it was pretty cool that you could combine stuff in MSBuild in a way it was never intended to be used. Even though it's not a proper programming language, I'm always amazed at what you can do with our existing constructs.
NeilAnonymous
December 15, 2006
<a href="http://forddor.ifastnet.com/">Ford</a>">http://forddor.ifastnet.com/">Ford</a> or [url=http://forddor.ifastnet.com/]Ford[/url] or http://forddor.ifastnet.com/Anonymous
July 28, 2008
How can i reset the taskparameter "Lines" if i want to read and write from and to another file? I have some problems if i try to write to a file in a new target, then i write the input from the earlier ReadFromFile job..Anonymous
August 18, 2008
Just a note - this method strips out tab characters and blank linesAnonymous
August 28, 2008
The comment has been removedAnonymous
September 02, 2008
Hi how can I specify duplicate files in the InFiles Item and have them read in? i.e. <InFiles Include="1.in;2.in;1.in"/> Cheers! NeilAnonymous
February 10, 2009
You can conatenate files like this: <ItemGroup> <TextFiles Include="*.txt" Exclude="final.txt"/> </ItemGroup> <Exec Command="echo y| type %(TextFiles.Identity) >> final.txt"/>Anonymous
October 19, 2009
>> <Exec Command="echo y| type %(TextFiles.Identity) >> final.txt"/> This unfortanately doesn't work if the files are UTF encoded with a BOM (Byte-order mark) since it will add the BOM at each seam.Anonymous
April 30, 2015
This method trims heading spaces and tabs. So, this isn't actual files concatenation.