5

I have a bunch of tables saved in separate files and folders which I have compiled with a master file, commenting the name of each file in the master file one by one and tediously renaming the resulting PDF output.

I have over one hundred tables produced over several months. Now I would like to recompile them all in a different style, so I'm looking for a way to automate the process.

Below is an unsuccessful attempt that builds on several suggestions found on this site, particularly this question.

To summarise in words what I tried to do in the code below:

  1. create files a.tex and b.tex to be used as inputs (these are my tables);
  2. define a command to store the file names as a list, a and b (no need to automate file naming);
  3. a foreach loop (package pgffor) to call each input file a.tex and b.tex inside a basic document header/preamble (standalone class) and save it with the name temp.tex;
  4. followed by a call to \immediate\write18{pdflatex... to run pdflatex on temp.tex;
  5. the intended output is two PDF files named a.pdf and b.pdf. I'm running this with shell-escape enabled.

Needless to say it's not working and help is appreciated!

% !TeX TXS-program:compile = txs:///pdflatex/[--shell-escape]
\documentclass{article}
\usepackage{pgffor}% \foreach
\usepackage{filecontents}
\begin{filecontents*}{a.tex}
  First file (a table without preamble)
\end{filecontents*}

\begin{filecontents*}{b.tex}
  Second file (a table without preamble)
\end{filecontents*}

\newcommand*{\ListOfFiles}{a,b}

\foreach \x in \ListOfFiles{%
  \begin{filecontents*}{temp.tex}%
    \documentclass{standalone}%
    %\usepackage{stylesforalltables}
    \begin{document}%
    \input{\x}
    \end{document}%
  \end{filecontents*}%
  \immediate\write18{pdflatex -jobname=\x\space temp}
}%
PatrickT
  • 2,923
  • 6
    why do you need to make a loop in tex? if I had a directory full of tex files I'd just write for i in *.tex; do pdflatex $i;done and get a directory full of pdf. (That's bash but you could do the same in any commandline . – David Carlisle Mar 17 '17 at 18:55
  • 1
    @DavidCarlisle - it seems the tables are not actually complete documents. So, he needs a way to process each table as a document fragment. Maybe for file in table*.tex; do ln -s $file temp.tex; pdflatex template.tex; mv template.pdf $(file%.tex).pdf; done. This assumes that names of all table source files start with table, and that the template.tex file sets up the desired document format and contains \input{temp} in the document body. – Michael Palmer Mar 17 '17 at 20:36
  • 1
    Please 1) don't use filecontents as argument of a command 2) don't use % at the end of line with \begin{filecontents*}{temp.tex}% 3) try \input{\jobname} instead of \input{\x}. – touhami Mar 17 '17 at 22:34
  • @DavidCarlisle, a bash/commandline solution would be perfectly acceptable for a one-off, but I'm also interested in a cross-platform solution that would be easy to explain to my co-authors (in this project I do not have co-authors, but in other cases I do, so I'm interested in learning of other ways). Thanks for the comment. – PatrickT Mar 18 '17 at 06:27
  • @MichaelPalmer, your interpretation is correct, thanks for the solution! – PatrickT Mar 18 '17 at 06:39
  • @touhami, thanks! not sure why \jobname instead of \x, but it's easy enough to remember. Is there a short explanation for the layman for why a loop over filecontents wouldn't work? – PatrickT Mar 18 '17 at 06:41
  • filecontents writes verbatim so in temp.tex we get \input{\x} and \x is undefined. – touhami Mar 18 '17 at 07:36
  • Thanks a lot touhami. By the way your answer and egreg's were a tie, as both answered my question and worked perfectly. I picked egreg's only because it was the closest to my original attempt, for no better reason. Both answers are great. Thanks again. – PatrickT Mar 18 '17 at 07:40
  • you're welcome, egreg's answer is better (as always). – touhami Mar 18 '17 at 13:58

2 Answers2

4

You can't use filecontents in the argument to another command. But you can define the master file in a separate filecontents environment. Call this compileall.tex (or whatever)

\documentclass{article}
\usepackage{pgffor}% \foreach
\usepackage{filecontents}

\begin{filecontents*}{master.tex}
\documentclass{standalone}
%\usepackage{stylesforalltables}
\begin{document}
\input{\jobname}
\end{document}
\end{filecontents*}

\begin{filecontents*}{a.tex}
  First file (a table without preamble)
\end{filecontents*}

\begin{filecontents*}{b.tex}
  Second file (a table without preamble)
\end{filecontents*}

\newcommand*{\ListOfFiles}{a,b}

\foreach \x in \ListOfFiles{%
  \immediate\write18{pdflatex -jobname=\x\space master}
}

\stop

However, it's simpler to have master.tex written as above and do, from the command line (assuming bash)

for i in {a,b}; do pdflatex -jobname=$i master; done
egreg
  • 1,121,712
  • Thanks! I prefer the non-command line solution, as I tend to edit documents with texstudio and compile them by pressing on the F12 key (my shortcut), plus I use MacOS, Linux, Windows almost indifferently (depending on whether I'm at home, the office, etc) and shell commands are not always cross-platform. But it's certainly good to have as a reference. – PatrickT Mar 18 '17 at 06:54
  • Note to self: As I have my tables saved in folders with the same name, I wrote \input{\jobname/\jobname} and it worked. – PatrickT Mar 18 '17 at 07:45
3

Here is a solution (with simple \write).

\documentclass{article}
\usepackage{pgffor}% \foreach
\usepackage{filecontents}

\begin{filecontents*}{a.tex}
  First file (a table without preamble)
\end{filecontents*}

\begin{filecontents*}{b.tex}
  Second file (a table without preamble)
\end{filecontents*}


\newcommand*{\ListOfFiles}{a,b}


\newwrite\temp
\foreach \x in \ListOfFiles{
\immediate\openout\temp=temp.tex
\immediate\write\temp{
    \string\documentclass{standalone}
    \string\begin{document}
    \string\input{\x}
    \string\end{document}
}
\immediate\closeout\temp
\immediate\write18{pdflatex -jobname=\x\space temp}
}%

\begin{document}
foo
\end{document}

Or (shorter) with \unexpanded

\immediate\write\temp{\unexpanded{%
    \documentclass{standalone}
    \begin{document} 
    \input{\jobname} 
    \end{document}}
touhami
  • 19,520
  • Excellent, thanks! I like the second solution better, with \unexpanded, as it makes it easier to type a longer preamble. – PatrickT Mar 18 '17 at 06:50