我如何提供使用 \write18 执行的逐字(未转义)命令行?

我如何提供使用 \write18 执行的逐字(未转义)命令行?

当使用\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 进行处理。

相关内容