\documentclass{article}
\begingroup\makeatletter\endlinechar=\m@ne\everyeof{\noexpand}
\edef\x{\endgroup\def\noexpand\TeXpath{\@@input|"which tex" }}\x
\begin{document}
File listing is
{\catcode`_=12 \ttfamily
\input{|"ls /usr" }
}
\TeX{} is \TeXpath
\end{document}
We must use \@@input
(the primitive \input
command) because \input
in LaTeX does assignments. The setting of \endlinechar
is to avoid a spurious space in the expansion of \TeXpath
.
When shell escape is active and the primitive \input
finds a |
, it accepts as input the standard output of the following shell command.
There should be a package by H. Oberdiek that does something of this kind.
Note An assignment is any TeX operation that gives a meaning or a value to a control sequence or register. During the \edef
operation, TeX expands all commands it finds between the braces until only unexpandable tokens remain, but doesn't perform any assignment; rather, something like \catch=22
(where \catch
is the name of a count register) remains completely inaltered. Since the definition of \input
in LaTeX is
\@ifnextchar\bgroup\@iinput\@@input
the implicit assignments performed by \@ifnextchar
would not be performed and both \@input
and \@@input
would be expanded, which results in a complete disaster. Conversely, the \input
primitive (that LaTeX saves as \@@input
) is expandable and its expansion consists in causing TeX to read the named file. One has, of course, to be careful about what this file contains, as also this will be expanded. So other precautions have to be taken when doing this kind of operations, depending on the nature of the tokens produced by the command we want to perform and this "solution" is only a skeleton for possible "real" applications.
Update 2019
After some years, things have changed and better methods are available.
For instance, with xparse
and expl3
the code can be improved:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\captureshell}{som}
{
\sdaau_captureshell:Ne \l__sdaau_captureshell_out_tl { #3 }
\IfBooleanT { #1 }
{% we may need to stringify the result
\tl_set:Nx \l__sdaau_captureshell_out_tl
{ \tl_to_str:N \l__sdaau_captureshell_out_tl }
}
\IfNoValueTF { #2 }
{
\tl_use:N \l__sdaau_captureshell_out_tl
}
{
\tl_set_eq:NN #2 \l__sdaau_captureshell_out_tl
}
}
\tl_new:N \l__sdaau_captureshell_out_tl
\cs_new_protected:Nn \sdaau_captureshell:Nn
{
\sys_get_shell:nnN { #2 } { } #1
\tl_trim_spaces:N #1 % remove leading and trailing spaces
}
\cs_generate_variant:Nn \sdaau_captureshell:Nn { Ne }
\ExplSyntaxOff
\begin{document}
\captureshell*[\TeXpath]{which tex} % we need to stringify it because of _
File listing is
{\ttfamily\captureshell{ls \jobname.*}\par}
\TeX{} is \texttt{\TeXpath}
\end{document}
We could add an error message if the user doesn't pass the -shell-escape
option for the LaTeX run.
Check also texosquery
(requires Java).
Use \@percentchar
instead of %
. You need to say \makeatletter
before the \write
and \makeatother
after it to allow for the @
in the macro name if the code isn't located in a package or class or already inside a \makeatletter
... \makeatother
block.
There are also \@backslashchar
for \
and also \@charlb
and \@charrb
for {
and }
. The are listed as "String constants" in my macros2e
document as mentioned in Documentation reference for LaTeX internal commands?
You can also now easily define new string macros for any set of characters with the new version of the newverbs
package.
E.g. to define a macro for the ampersand use:
\usepackage{newverbs}[2011/07/24]
\Verbdef\amp{&}
Note that spaces behind macros are removed also in a \write
statement, so you might need to manually insert one using \space
.
Best Answer
I don't think that cmd.exe was ever directly allowed (in restricted mode). You need to run your document with
--shell-escape
.When I try your document I get a prompt in the window where pdflatex compiled the document.
If you want a new cmd.exe windows you should probably use
(again --shell-escape is needed).