The problem

I need to generate a file with very simple structure, just a LaTeX file with a few include statements. Until today, I was copying a template and manually changing it. This was slow, redundant, and error prone. It makes more sense to just generate the files from the template instead. I wanted to use bash for this rather than a scripting language, because then it will connect better with the whole GNU Make workflow of the project.

The solution

I started by putting the template in the Makefile and using echo, as I normally do. This gave me some problems, so I started looking into alternatives that would let me keep the template as a separate file. Most people recommend printf as a more robust alternative to echo. The problem was, how to pass printf the FORMAT argument from a file? Use xargs.

Here’s a simple example. First you’ll need a format.txt file, or whatever you choose to call it.

$ printf "%%s and %%s\n" > format.txt

The %% just escapes the special character % for printf, so the contents of template.txt are %s and %s.

$ cat format.txt
%s and %s

We can use it as follows:

$ cat format.txt | xargs -0 -I{} printf {} A B
A and B

We read this command as printf <contents of format.txt> A B. xargs always makes me do some mental gymnastics. The -0 flag prevents xargs from messing with the actual contents, i.e. removing whitespace. -I{} allows me to take the text and pass it as the first argument with printf {} .... Otherwise it would be the last argument.

Here’s how I actually use it in my Makefile:

%.tex: tex/%.tex texformat.txt preamble.tex
	cat texformat.txt | xargs -0 -I{} printf {} $< $< > $@