制作多个文件的“独立”版本:所有文档都在一个 .tex 文件中

制作多个文件的“独立”版本:所有文档都在一个 .tex 文件中

免责声明:这个问题是不是与……相关独立包裹。

在撰写文章时,我将内容拆分到几个文件中,以显著简化版本控制。在撰写本文时,我的大多数文章如下所示:

我的拆分文件.tex:

\documentclass{article}
\input{packages}
\input{macros}
\addbibresource{short,biblio}

\begin{document}
    \input{content}
\end{document}

文件 content.tex 本身包含几个文件,包含在 \input 命令中。

写作结束后,我更喜欢保留一个文件,以便于轻松编辑、共享和备份。

感谢 bibtool,我可以轻松地从我的(巨大的).bib 文件中提取相关内容:

bibtool -x my-split-file.aux -o standalone.bib

之后,我可以将 .bib 文件的相关部分包含到我的 .tex 中,这要归功于文件内容包裹。

有没有办法对 .tex 文件执行相同操作?我想制作一份文档,其中包含以下内容:

  • 用所包含文档的实际内容替换输入的命令;
  • 提取用到的宏并将其他宏放在一边;
  • (奖励)以“明智”的方式删除注释:不是那种不加空格就能转到新行的注释(就像

    I start a sentence%
    \footnote{I can start my footnote on a new line, for readability of the source code}
    and then go back to my sentence.
    

    ),而是说“这个证明可能是错误的” ;-)编辑:它可能还应该删除因删除注释而产生的空行……

我并不惧怕一些Linux脚本!

编辑:由于脚本似乎是处理该问题的最佳方法,因此我希望脚本自动运行 bibtool,提取参考书目的相关部分并将其放入文件内容环境。

编辑:如果我错了请纠正我,但我知道 5 种定义(我称之为)宏的方法:

  • \newcommand
  • \newcommand*
  • \renewcommand
  • \renewcommand*
  • \def

但是,我的 macros.tex 文件总是充斥着\hyphenation\DefineBibliographyStrings其他 biblatex 选项,\DeclareDocumentCommand\NewDocumentCommand来自解析包)、、、\DeclareMathOperator等等\DeclareMathSymbol

也许 Pouya 提出的方法应该“逆转”并删除未使用的宏(用其中一种方法定义),但其余部分保持原样(而如果我理解正确的话,Pouya 只保留使用的宏)。

答案1

免责声明!

使用此产品需要您自担风险。并备份所有内容!此外,请将此视为一个起点,因为它远非完美。


我编写了一个小型 bash 脚本,它可以以相当通用的方式完成您的所有三个要求,但是,如果您根据项目结构进行个性化设置,效果会更好。

它应该与任何标准 Unix shell(包括 OS X)兼容。除此之外,你还需要乳胶膨胀它将负责内联你的文件。

在这里,我将解释脚本的每个部分如何工作以及它如何完成它的工作。虽然我建议单独使用它的各个部分(而不是作为一个整体运行)。也许,它能让你更好地控制你想要做的事情。

#!/bin/bash

# Defining some variable for you files:
# 1. The file containing all your macros
# 2. The file that the script uses to contain trimmed (i.e. only used) macros
# 3. Main .tex file
ORIGINAL_MACRO_FILE=macros_original.tex
TRIMMED_MACRO_FILE=macros_original_trimmed.tex
MAIN_FILE=paper.tex

if [[ -f macros_regex.txt || -f macros_regex_trimmed.txt || -f $TRIMMED_MACRO_FILE ]]; then
    echo "Some temp files are already here. Please get rid of them first..."
    exit 0
fi

# Making a trimmed version of macro files:
echo -ne '\\b(' > macros_regex.txt
echo -ne '\\b(' > macros_regex_trimmed.txt
grep -Po '(?<=\\def\\)(.+?)(?=\{)' $ORIGINAL_MACRO_FILE | tr '\n' '\|' >> macros_regex.txt
sed -i 's/.$/\)\\b/' macros_regex.txt
grep -Porh --exclude=$ORIGINAL_MACRO_FILE $(cat ./macros_regex.txt) *.tex | sort | uniq | tr '\n' '\|' >> macros_regex_trimmed.txt
sed -i 's/.$/\)\\b/' macros_regex_trimmed.txt
grep -P $(cat ./macros_regex_trimmed.txt) $ORIGINAL_MACRO_FILE > $TRIMMED_MACRO_FILE

# Backing up the original macro file:
cp $ORIGINAL_MACRO_FILE $ORIGINAL_MACRO_FILE\_backup
mv $TRIMMED_MACRO_FILE $ORIGINAL_MACRO_FILE

# Inline the file to collect have one big file. This is needed for finding unused macros
perl latexpand --keep-comments $MAIN_FILE > inlined_paper.tex 
rm macros_regex.txt macros_regex_trimmed.txt

# Putting back the original macro files:
rm $ORIGINAL_MACRO_FILE
mv $ORIGINAL_MACRO_FILE\_backup $ORIGINAL_MACRO_FILE

# Removing comments
sed -ri '/\%[^\n].+/ d' inlined_paper.tex

# Removing blank lines if you want
sed -ie '/^$/ d' inlined_paper.tex

它需要两个文件才能启动:

ORIGINAL_MACRO_FILE=macros_original.tex
MAIN_FILE=paper.tex

包含所有宏和主文件的文件texTRIMMED_MACRO_FILE是一个临时文件,用于保存所用宏的列表。然后检查此临时文件以及另外两个文本文件是否存在,如果不存在,则继续(请注意,脚本完成后将删除这些辅助文件)。

它首先解决了你的第二个问题!它使用这个正则表达式在你的宏文件中进行搜索(?<=\\def\\)(.+?)(?=\{),并收集姓名所有宏。在我的示例中,我假设宏的形式为\def\name{...,但是,如果您使用其他宏定义命令,则以下是一些正则表达式:

  • (?<=\\newcommand\{\\)(.+?)(?=\})为了新命令
  • (?<=\\renewcommand\{\\)(.+?)(?=\})为了更新命令
  • (?<=\\newcommand\*\{\\)(.+?)(?=\})为了新命令*

您可以在正则表达式中使用逻辑运算符or( )来获得多个上述定义,例如|

((?<=\\def\\)|(?<=\\renewcommand\{\\))(.+?)(?=\{)

使用defrenewcommand语法。

macros_regex.txt然后它以以下形式存储所有宏名称:

\b(amacro|anothermacro|foo|bar|etc)\b

然后使用下一行,检查已使用以下哪一个宏:

grep -Porh --exclude=$ORIGINAL_MACRO_FILE $(cat ./macros_regex.txt) *.tex | sort | uniq | tr '\n' '\|' >> macros_regex_trimmed.txt

事情是这样的:grep -Porh意味着使用 perl-regex 在文件内容中搜索,仅打印匹配的行,递归并省略文件名。它还排除了您的原始宏文件,因为它显然会与所有模式匹配。最后,我们提供我们之前创建的模式,$(cat ./macros_regex.txt)然后在所有tex文件中进行递归搜索。

然后对结果进行排序,并删除重复项(分别通过管道连接到sortuniq)。然后,我们再次以以下形式创建此输出的正则表达式

\b(anothermacro|foo|etc)\b

但这次它只包含使用过的宏。最后,grep此文件包含原始宏文件并将数据保存在 中TRIMMED_MACRO_FILE。总结一下,如果我们有一个以下形式的文件:

% original macros
\def\bfa{{\mbox{\boldmath $a$}}}
\def\bfb{{\mbox{\boldmath $b$}}}
\def\bfc{{\mbox{\boldmath $c$}}}
\def\bfd{{\mbox{\boldmath $d$}}}
\def\bfe{{\mbox{\boldmath $e$}}}
\def\bff{{\mbox{\boldmath $f$}}}

经过这一阶段,我们有:

% trimmed macro file
\def\bfb{{\mbox{\boldmath $b$}}}
\def\bfc{{\mbox{\boldmath $c$}}}
\def\bff{{\mbox{\boldmath $f$}}}

这是您的项目中使用的宏的定义。

现在,我在这里解释一下为什么我首先解决了你的第二个问题:D。这个想法是,一旦我们有了文件的修剪版本,就交换原始宏文件和修剪后的宏文件,然后扩展/内联所有内容。这是通过备份原始宏文件、重命名修剪后的文件并最终用于内联latexpand所有内容来完成的。

perl latexpand --keep-comments $MAIN_FILE > inlined_paper.tex

latexpand是一个处理\input和的perl 程序\include。如您所见,我已使用标志--keep-comments来保留注释。如果您不这样做,它将很好地清除所有注释,但是,此清除包括您提到的需要保留的注释。清除注释是一个简单的sed单行命令,将\%[^\n].+模式替换为空白。该正则表达式表示百分号后面不是直接跟换行符,而是跟一个或多个任何类型的字符。最后,如果您想删除空行,可以使用最后一个命令,即sed -ie '/^$/ d' inlined_paper.tex或以其他方式对其进行注释。


如您所见,这是一个可以完成工作的脚本,但它应该根据您的项目结构和命令进行定制。再次,我建议单独使用此代码的不同部分,而不是将其作为一个整体运行。例如,删除注释的行是一个有用的单行独立代码。

最后,我建议坚持使用它,latexpand因为它是为此目的而设计的专业工具,而不是我创建的这个脚本,因为我的其他代码未编译(这说明了很多问题!)我感到无聊。

cpPS 我假设读者对基本的 bash 命令(例如、mv和)相当熟悉grep。如果您发现此答案不够详细,请发表评论。

相关内容