💾 Archived View for republic.circumlunar.space › users › johngodlee › posts › 2020-04-25-latex-main.… captured on 2023-09-08 at 16:20:43. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-04-19)

-=-=-=-=-=-=-

Compiling a single master.tex from a modular document

DATE: 2020-04-25

AUTHOR: John L. Godlee

I've recently submitted a paper to a peer reviewed journal. During the final proofing process it was clear that the editors at the journal had taken my original paper.tex file, which calls a load of other .tex files using \input{}, as well as a .bib file with \bibliography{}, and subbed in the contents of those files to form one .tex file which could then be compiled on its own, without the additional files originally called by my paper.tex.

It seemed like this process could be automated somewhat, so I set about writing a bash script.

#!/usr/bin/env bash

# Run latexmk
latexmk $1

# Get filename without extension
base="${1%.*}"

# Create main.tex
cp "${base}.tex" "main.tex"

# Create \input{} filepaths array
inputs=($(grep -E '\\input{.*}' $1 | sed 's/.*{\([^]]*\)}.*/\1/g'))

# Create \input{} line number array
inputlines=($(grep -n '\\input{.*}' $1 | cut -f1 -d: ))

# Loop over each element of both array to create a sed statement
# which replaces the \input{} lines with the contents of the referenced file
for ((i=0;i<${#inputlines[@]};++i)); do
   printf -v s '%s%s\n%s\n' "$s" "${inputlines[i]}r ${inputs[i]}" "${inputlines[i]}d"
done

# Run sed 
sed -i.bak -e "$s" main.tex

# Find bibliography line number
bibline="$(grep -n '\\bibliography{.*}' main.tex | cut -f1 -d: )"

# Replace \bibliography{} with formatted contents of
# .bbl file generated by latexmk
sed -i.bak -e "${bibline}r ${base}.bbl" -e "${bibline}d"  main.tex

# Clean up intermediate files
rm main.tex.bak
latexmk -C

First the script runs latexmk to compile the intermediate files and a .pdf. Then the script creates two array variables, one containing the filepaths of every file that is called by \input{} and the other containing the line numbers in paper.tex of each of those \input{} lines. Then the script runs a for loop which creates a big long multi-part sed statement, which replaces the lines with input{} with the contents of that file. As a side note, this is the first time I've really used the sed r operator, and it looks super useful. Finally the script does similar but without a for loop to replace the bibliography command with the contents of paper.bbl, which is a TeX formatted file containing the bibliography, generated by latexmk from the .bib file. After that there is just some clean up to remove intermediate files and you're left with main.tex, which can then be sent off to reviewers or used for final proofing before publication, without the hassle of handling multiple documents. While multiple documents is useful during document creation, I feel it's less useful when you are trying to typeset the final document.

I got a lot of help and inspiration from the following StackExchange posts:

And from this question which I asked myself to help figure out the for loop bit:

1: https://tex.stackexchange.com/questions/514153/dealing-with-strict-rules-for-paper-submission-using-latex

2: https://tex.stackexchange.com/questions/25713/how-do-i-combine-several-tex-files-into-one

3: https://tex.stackexchange.com/questions/62232/generating-a-single-tex-file-by-merging-different-tex-files

4: https://stackoverflow.com/questions/60980245/insert-file-contents-at-line-number-from-bash-arrays/60989942?noredirect=1#comment107902183_60989942