0

I want to \input"|..." to invoke a shell command and consume its output as LaTeX code.

In particular, I want to write something like:
\expandableShellCmdProtectCmdArgsWithBackslashes{echo}{2(3)}
and have it call the shell with:
echo \2\(\3\)
escaping all the "arg" characters with backslashes.
The reason is to escape shell-special characters like (.

The desired result is that echo prints 2(3) and that is consumed as LaTeX input.

The attempt below via \str_map_inline:nn + \c_backslash_str fails, producing strange slanted double-quote symbols in place of all of the locations where I'd expect backslashes before invoking the shell, and the actual shell command executed doesn't include most of the desired input.

How can I prepend a backslash before each character of an \input command?

\documentclass[11pt]{article}

\begin{document}

\makeatletter \newcommand{\expandableShellCmd}[1]{ @@input"|#1"} % \input is not expandable \makeatother

\ExplSyntaxOn \NewDocumentCommand{\protectWithBackslashes}{m} { % prepends every character of the input with a backslash \str_map_inline:nn{#1}{\c_backslash_str##1} } \NewDocumentCommand{\expandableShellCmdProtectCmdArgsWithBackslashes}{mm} {% shell command, args % Pass the input string as a cmd to the shell, but prepend each char in the args with a backslash \exp_args:Ne\expandableShellCmd{#1~\protectWithBackslashes{#2}} % Fully expand the argument before invoking the shell } \ExplSyntaxOff

\expandableShellCmdProtectCmdArgsWithBackslashes{echo}{2(3)} % want to run in shell "echo \2(\3)" which produces output "2(3)" % However, this produces PDF output: % “2“(“3“)” % and the console output shows that the shell command executed was (without quotes) "|echo "

\end{document}

1 Answers1

3

Commands defined with \NewDocumentCommand are not touched by e-expansion; also \str_map_inline:nn has the same feature, so calling \exp_args:Ne does nothing at all.

And I don't think you need to worry about expandability.

\documentclass{article}

\ExplSyntaxOn

\tl_new:N \l_fink_shell_output_tl

\NewDocumentCommand{\DoShellCommand}{O{}m} { \fink_shell_do:nn { #1 } { #2 } }

\NewExpandableDocumentCommand{\protectWithBackslashes}{m} { % prepends every character of the input with a backslash \fink_shell_addbackslash:n { #1 } }

\cs_new_protected:Nn \fink_shell_do:nn { \sys_get_shell:nnN { #2 } { #1 } \l_fink_shell_output_tl \tl_use:N \l_fink_shell_output_tl } \cs_generate_variant:Nn \fink_shell_do:nn { ne }

\cs_new:Nn \fink_shell_addbackslash:n { \str_map_function:nN { #1 } __fink_shell_addbackslash:n } \cs_new:Nn __fink_shell_addbackslash:n { \c_backslash_str #1 }

\NewDocumentCommand{\DoShellCmdProtectCmdArgsWithBackslashes}{mm} {% shell command, args % Pass the input string as a cmd to the shell, but prepend each char in the args with a backslash \fink_shell_do:ne {} {#1~\fink_shell_addbackslash:n {#2}} % Fully expand the argument before invoking the shell } \ExplSyntaxOff

\begin{document}

\DoShellCmdProtectCmdArgsWithBackslashes{echo}{2(3)}

\end{document}

The log file has

(|echo \2\(\3\))
egreg
  • 1,121,712