在研究预编译序言时,通常创建格式文件的命令如下
pdftex -ini -jobname="foo" "&pdflatex" mylatexformat.ltx foo.tex
阅读后pdftex --help
,我了解到:
-jobname=STRING set the job name to STRING
-ini be pdfinitex, for dumping formats; this is implicitly
true if the program name is `pdfinitex'
其余参数由以下行指定
or: pdftex [OPTION]... &FMT ARGS
所以FMT
是pdflatex
,并且ARGS
是mylatexformat.ltx foo.tex
。
问题:
- 这里指定了什么
ARGS
? - 为什么会导致生成前导码?
- 另外,文档在哪里?
- 为什么文档
mylatexformat
建议对该foo.tex
部分使用三重引号?
答案1
命令行格式
tex &FMT ARGS
源自古代,当时 Unix 命令行并不像今天这样常用,并导致了经典的 TeX 行为:读取格式后&FMT
,TeX 会扫描第一个字母;如果是,\
则将命令行的其余部分解释为文档的第一行。这不完全是您的示例:第一个字母m
在您的示例中,因此 TeX 将以下单词(没有空格)解释为文件名并执行\input mylatexformat.ltx
。这是一种非常常见的情况;不常见的是,您使用的文件没有\end
或\dump
原语(并且\end
或\dump
原语不会从使用的宏中扩展)。这是 TeX 从命令行的其余部分然后从终端读取下一个数据的情况。文件mylatexformat
以 结尾
\expandafter\input\endinput
,因此\input
调用命令,但其参数未在文件中给出mylatexformat.ltx
,因此 TeX 尝试从命令行的其余部分读取参数,这意味着\input foo.tex
完成。
关于引号。命令解释器会删除它们,并更详细地解释其中的文本。echo """hello"""
例如,尝试 。它会打印hello
。但我不知道为什么在文档中推荐它们。
答案2
看来我只需要更仔细地看一下文档。
Usage: pdftex [OPTION]... [TEXNAME[.tex]] [COMMANDS] or: pdftex [OPTION]... \FIRST-LINE or: pdftex [OPTION]... &FMT ARGS
在 TEXNAME 上运行 pdfTeX,通常会创建 TEXNAME.pdf。在读取 TEXNAME 后,任何剩余的命令都将作为 pdfTeX 输入处理。如果 TEXNAME 的第一行是 %&FMT,并且 FMT 是一个现有的 .fmt 文件,则使用它。否则使用“NAME.fmt”,其中 NAME 是程序调用名称,最常见的是“pdftex”。
或者,如果第一个非选项参数以反斜杠开头,则将所有非选项参数解释为一行 pdfTeX 输入。
或者,如果第一个非选项参数以 & 开头,则下一个单词将作为要读取的 FMT,覆盖所有其他单词。 任何剩余的参数都按上述方式处理。
如果没有指定参数或选项,则提示输入。
换句话说,ARGS
是“任何剩余的参数”,这意味着明确地写成
Usage: pdftex [OPTION]... [TEXNAME[.tex]] [COMMANDS]
or: pdftex [OPTION]... \FIRST-LINE
or: pdftex [OPTION]... &FMT [TEXNAME[.tex]] [COMMANDS]
or: pdftex [OPTION]... &FMT \FIRST-LINE
也就是说mylatexformat.ltx
变成了文件名[TEXNAME[.tex]]
,也foo.tex
就是[COMMANDS]
“作为 pdfTeX 输入处理”。
实验以推断确切的行为(仅限 Linux 上的 TeX Live)
(不参考源代码pdftex-changes.pdf
)
进行一些实验来了解“命令”如何工作:
echo '\edef\a{' > a.tex
pdftex a.tex 'bc}' </dev/null
出现“失控定义”错误。(这个很清楚:将 \everyeof 和 \endlinechar 与 \scantokens 结合使用)
echo '\edef\a{\noexpand' > a.tex
pdftex a.tex 'bc}\message{|\a|}' </dev/null
显示\a
已分配bc
,这意味着在之后EOF
,的命令被作为“TeX 代码行”放置,如下所述。
我们也\noexpand
可以使用
echo '\endlinechar=`d\edef\a{' > a.tex
echo 'bc' >> a.tex
echo 'bc\noexpand%' >> a.tex
pdftex a.tex 'bc' '}\message{|\a|}\show' </dev/null
这将输出|⟨space⟩ bcdbcbc ⟨space⟩|
,并且\show
最后不会显示任何内容或给出任何错误。
如果有多个参数,则用空格连接它们,不是解释为多行 TeX 代码。
(以上相当于执行以下 TeX 代码
\endlinechar=`d\edef\a{ ■¹
bc ■²
bc\noexpand% ■³
⟨EOF⟩
bc ∘⁴ }message{|\a|}\show ■⁵
分析:(每一条■
代表一条endlinechar
)
- ■¹ 已经固定为等同于读取第一行的字符 13。
- ■² 变成字符
d
。 - ■³ 被注释掉。
- ∘⁴ 是不是endlinechar,它只是一个空格。
- 我们稍后会看看
■⁵
。
我们可以进行更多的实验:
pdftex '\catcode13=12\def~{\show}~' </dev/null
结果是the character ^^M.
这意味着字符代码为 13 的“(未标记的)字符”附加在“伪线”之后。
代码备注mylatexformat.ltx
与之不同的是\edef
,诸如\input
(原始命令)这样的命令可以跨越 EOF 边界工作:
echo '\message{hello world!!!}' > "hello world.tex"
echo '\input' > a.tex
pdftex a.tex '"hello world.tex"' </dev/null
hello world.tex
(这里输入打印消息的内容)
\endinput
并且只要它已经位于文件末尾,那么(可扩展)实际上是无用的。
mylatexformat.ltx
对文档中的注释进行备注
另一方面,我怀疑三引号的建议是因为 这是在 Windows 中转义命令引号的方法,尽管我还没有测试过。
因此执行的 TeX 代码如下所示
\input "file name.tex"
代替
\input file name.tex
显然后者是行不通的。
另外,正如评论中提到的mylatexformat.ltx
:
%% Trick lookahead to allow mylatex.ltx and the document filename to be
%% given on the same command line. (initex &latex mylatex.ltx {abc.tex})
\expandafter\input\endinput%
\endinput
因此,诸如
pdftex -ini -jobname="foo" "&pdflatex" mylatexformat.ltx "{foo.tex}"
也可以。
允许获取文件名而无需额外引用
附注:根据上述知识:
在 TeX 代码中,无法区分用户编写的
pdftex file.tex firstargument secondargument
和
pdftex file.tex "firstargument" "secondargument"
因为在这两种情况下,参数都与空格连接。
我们可以设计一个函数,
\input
从命令行给出文件名,而不需要额外的引号,只要文件名是命令行上的完整内容。cat > a.tex << 'EOF' \catcode `\^^M 2 % \def \process {\catcode `\^^M 5 \input {\filename}}% \afterassignment \process % \edef \filename {\noexpand% EOF # alternatively: cat > a.tex << 'EOF' \catcode `\^^M 12 % \def \process #1^^M{\catcode `\^^M 5 \input {#1}}% \expandafter \process \noexpand% EOF # then these can be used (as mentioned above, they're equivalent and indistinguishable) pdftex a.tex hello world.tex </dev/null pdftex a.tex "hello world.tex" </dev/null
如果需要,需要采取额外的预防措施来处理
{
或}
处理文件名(可能仅用于学术目的)。