![我如何提供使用 \write18 执行的逐字(未转义)命令行?](https://linux22.com/image/235709/%E6%88%91%E5%A6%82%E4%BD%95%E6%8F%90%E4%BE%9B%E4%BD%BF%E7%94%A8%20%5Cwrite18%20%E6%89%A7%E8%A1%8C%E7%9A%84%E9%80%90%E5%AD%97%EF%BC%88%E6%9C%AA%E8%BD%AC%E4%B9%89%EF%BC%89%E5%91%BD%E4%BB%A4%E8%A1%8C%EF%BC%9F.png)
当使用\write18
执行 shell 命令时,有些情况下需要在命令行中使用大量反斜杠字符串和其他“特殊” LaTeX 字符(例如,如果需要正则表达式,或者使用 awk 时)。
有一种方式可以很方便地输入命令,就像它在命令行上使用时应该显示的那样(即不需要使用\string
等),并逐字解析它,并将其作为参数提供给\write18
。有哪些方法可以实现这一点?
答案1
你可以试试
\write18{\unexpanded{...}}
为了避免重复#
标记并使用%
,您可以定义
\def\exec{\begingroup\setexeccatcodes\innerexec}
\def\setexeccatcodes{\catcode`\#=12 \catcode`\%=12 }
\def\innerexec#1{\immediate\write18{\unexpanded{#1}}\endgroup}
但是您不能\exec
在另一个命令的参数中使用,因为这会冻结类别代码。如果您需要它,还必须使用\scantokens
。括号必须匹配,但这应该不是问题。
Martin Scharrer 建议的另一种可能性是使用\detokenize
:
\def\exec#1{\immediate\write18{\detokenize{#1}}}
但是,如果在参数中使用反斜杠,则可能会插入不必要的空格。优点是此宏可以用作其他命令的参数。
答案2
egreg 已经回答了 e-TeX 可用的典型情况。在原始的 TeX-82 程序中,您可以使用令牌寄存器有效地完成相同的操作
\newtoks\mytoks
\mytoks{<commands-go-here>}
\immediate\write18{\the\mytoks}
(这是因为标记寄存器在上下文中只扩展一次\write
,类似于它们在内部的行为\edef
。该\unexpanded
解决方案有效地做了同样的事情而不需要赋值操作。)
答案3
由于xparse
几个月前引入了逐字参数类型,所以这变得非常容易。
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\commandline}{v}
{ \immediate \write 18 { \tl_to_str:n {#1} } }
\ExplSyntaxOff
\commandline|echo "Hello World! @#$%^"|
\stop
答案4
尝试使用该bashful
包:
\bash
echo "\documentclass{Article}\begin{document}Hello, World!\end{document}" > try.tex
latex try.tex
\END
应该可以按预期工作,即从 latex 内部生成一个 latex 文件,然后将其提交给 latex 进行处理。