我正在尝试对依赖于 TeX 文件内部设置的某些数据进行 shell 处理。为此,我想要\immediate\write18
一个依赖于 的命令\usekomavar
,但pdflatex
会抱怨额外的}
。
口粮:
\documentclass{scrlttr2}
\newcommand\x[1]{hello #1}
\begin{document}
\begin{letter}{Person} % <- toname should be 'Person'
\opening{Opening}
\immediate\write18{echo 'none' > \jobname-none.txt} % fine
\immediate\write18{echo '\x{world}' > \jobname-x.txt} % fine
\immediate\write18{echo '\usekomavar{toname}' > \jobname-toname.txt} % error
\closing{Closing}
\end{letter}
\end{document}
具体来说,它告诉我:
$ pdflatex --shell-escape mre.tex
...snip...
! Argument of \reserved@a has an extra }.
<inserted text>
\par
l.12 ...usekomavar{toname}' > \jobname-toname.txt}
重要的是,我不想逃避命令。文件内容应该是Person
,而不是\usekomavar{toname}
在运行命令之后。
答案1
KoMa 变量基本上是以名称 保存的宏\scr@VARNAME@var
。\usekomavar
是一个强大的宏,用于检查变量是否已定义以及后面是否有星号,如果是,则执行其他操作。 如果您准备放弃这些检查,则只需使用\csname scr@VARNAME@var\endcsname
。 最坏的情况:KoMa 变量未定义,并且什么也没发生。
\immediate\write18{echo '\csname scr@toname@var\endcsname' > \jobname-toname.txt}
答案2
也可以使用可选参数\usekomavar
。因此我必须定义一个新的宏,它将文件的内容作为其最后一个参数。
\newcommand\writetofile[2]{% \writetofile{<file>}{<content>}
\immediate\write18{echo '#2' > #1}%
}
然后就可以使用
\usekomavar[\writetofile{\jobname-toname.txt}]{toname}
以获得期望的结果。
例子:
\documentclass{scrlttr2}
\newcommand\x[1]{hello #1}
\newcommand\writetofile[2]{% \writetofile{<file>}{<content>}
\immediate\write18{echo '#2' > #1}%
}
\begin{document}
\begin{letter}{Person} % <- toname should be 'Person'
\opening{Opening}
\immediate\write18{echo 'none' > \jobname-none.txt}% fine
\immediate\write18{echo '\x{world}' > \jobname-x.txt}% fine
\usekomavar[\writetofile{\jobname-toname.txt}]{toname}%
\closing{Closing}
\end{letter}
\end{document}
或者
\documentclass{scrlttr2}
\newcommand\x[1]{hello #1}
\newcommand\writetofile[2]{% writetofile{<file>}{<content>}
\immediate\write18{echo '#2' > #1}%
}
\newcommand\writekomavar[2]{% \writekomavar{<file>}{<variable>}
\usekomavar[\writetofile{#1}]{#2}%
}
\begin{document}
\begin{letter}{Person} % <- toname should be 'Person'
\opening{Opening}
\immediate\write18{echo 'none' > \jobname-none.txt}% fine
\immediate\write18{echo '\x{world}' > \jobname-x.txt}% fine
\writekomavar{\jobname-toname.txt}{toname}%
\closing{Closing}
\end{letter}
\end{document}
答案3
正如 Ulrike 所说,\usekomavar
不可扩展,但可以轻松创建功能等效的可扩展版本。不可扩展意味着该命令在其处理过程中执行赋值,因此在 或 内使用时会失败\edef
。\write
下面的命令仅使用可扩展命令,因此在 内\write
它会扩展到变量的值。
\documentclass{scrlttr2}
\newcommand\x[1]{hello #1}
\usepackage{xparse}
\ExplSyntaxOn
\NewExpandableDocumentCommand\xusekomavar{sO{\use:n}m}
{
\IfBooleanTF{#1}%
{ \__bitmask_usekomathing:nnn {name} }
{ \__bitmask_usekomathing:nnn {var} }
{#2} {#3}
}
\cs_new:Npn \__bitmask_usekomathing:nnn #1 #2 #3
{
\cs_if_exist:cTF { scr@#3@var }
{ \exp_args:Nnc \use:n {#2} { scr@#3@#1 } }
{ \msg_expandable_error:nnn { bitmask } { undefined-komavar } {#3} }
}
\msg_new:nnn { bitmask } { undefined-komavar }
{ KOMA-Script~variable~`#1'~not~defined. }
\ExplSyntaxOff
\begin{document}
\begin{letter}{Person} % <- toname should be 'Person'
\opening{Opening}
\immediate\write18{echo 'none' > \jobname-none.txt} % fine
\immediate\write18{echo '\x{world}' > \jobname-x.txt} % fine
\immediate\write18{echo '\xusekomavar{toname}' > \jobname-toname.txt} % error
\closing{Closing}
\end{letter}
\end{document}