How can I provide a verbatim (unescaped) commandline for executing with \write18?
You can try
\write18{\unexpanded{...}}
In order to avoid doubled #
marks and to use %
, you can define
\def\exec{\begingroup\setexeccatcodes\innerexec}
\def\setexeccatcodes{\catcode`\#=12 \catcode`\%=12 }
\def\innerexec#1{\immediate\write18{\unexpanded{#1}}\endgroup}
However you can't use \exec
in the argument of another command, because this freezes category codes. Should you need it, one has to work also with \scantokens
. Braces must be balanced, but this should not be a problem.
Another possibility, suggested by Martin Scharrer, is to use \detokenize
:
\def\exec#1{\immediate\write18{\detokenize{#1}}}
which however might insert unwanted spaces in case backslashes are used in the argument. The advantage is that this macro can be used in arguments to other commands.
egreg has an answered for the typical case where e-TeX is available. In the original TeX-82 program you'd do effectively the same using a token register
\newtoks\mytoks
\mytoks{<commands-go-here>}
\immediate\write18{\the\mytoks}
(This works because token registers are only expanded once in \write
contexts, in analogy to their behaviour inside \edef
. The \unexpanded
solution effectively does the same thing without needing the assignment operation.)
With xparse
's verbatim argument type introduced a couple of months ago, this is quite easy.
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\commandline}{v}
{ \immediate \write 18 { \tl_to_str:n {#1} } }
\ExplSyntaxOff
\commandline|echo "Hello World! @#$%^"|
\stop