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}
3
  • do you really want to \ quote every character? it's usually easier to ' delimit the entire string, then just use \' for ' Commented Dec 28, 2022 at 21:07
  • OT1 fonts have open quotes in the \ slot you would need \texttt or better add \usepackage[T1]{fontenc} but then you get this Commented Dec 28, 2022 at 21:20
  • My usual vote is for the simplest code to understand. \ before every character is conceptually simpler than ' at the ends + special protection for ' in the middle.
    – David Fink
    Commented Dec 29, 2022 at 0:36

1 Answer 1

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\))

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .