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}
}%
  • 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 6:27
  • @MichaelPalmer, your interpretation is correct, thanks for the solution! – PatrickT Mar 18 '17 at 6:39
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
  • 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 6: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 7: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}}
  • 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 6:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.