Expanda \def em \write18

Expanda \def em \write18

Eu defini o seguinte comando:

\newcommand{\formatcommand}[1]{
    \def\temp{#1}
    \def\s{\ifx\temp\empty empty\else not empty\fi}
    echo "\s"
}

Isso funciona corretamente:

\formatcommand{}
\formatcommand{ }

amostra

No entanto, ao usar o comando acima dentro \write18,

\immediate\write18{\formatcommand{}}

o \defs parece não estar se expandindo, já que estou recebendo \def is not an executable..., o que significa que \write18enviou o corpo \formatcommand{}sem expandi-lo para a linha de comando. Como isso pode ser consertado?

MWE

\documentclass[border=1cm]{standalone}


\begin{document}

\newcommand{\formatcommand}[1]{
    \def\temp{#1}
    \def\s{\ifx\temp\empty empty\else not empty\fi}
    echo "\s"
}

\formatcommand{}
\formatcommand{ }

\immediate\write18{\formatcommand{}}

\end{document}

Responder1

Quando o TeX escreve o conteúdo de um \writecomando, ele expande todo o material de forma semelhante ao que acontece em uma \edefdefinição, ou seja, todos os comandos expansíveis são expandidos, mas nenhuma execução acontece. As definições de macro (ou outras atribuições) não são expansíveis, portanto, os \defs permanecem no fluxo de entrada quando são escritos como comandos shell.

A solução é usar um teste totalmente expansível para uma lista de tokens vazia, como a seguinte \ifemptymacro:

\makeatletter
\newcommand\ifempty[1]{%
    \if\relax\detokenize{#1}\relax
        \expandafter\@firstoftwo
    \else
        \expandafter\@secondoftwo
    \fi
}
\makeatother

\newcommand{\formatcommand}[1]{
    echo "\ifempty{#1}{empty}{not empty}"
}

Responder2

Geralmente eu recomendo a solução siracusa'a, mas se você usar LuaTeX, há outro truque que você pode usar se o seu problema não puder ser escrito de maneira expansível:

LuaTeX possui primitivas \immediateassignmente \immediateassignedque permitem \defs expansíveis:

\documentclass[border=1cm]{standalone}


\begin{document}

\newcommand{\formatcommand}[1]{
    \immediateassignment\def\temp{#1}
    \immediateassignment\def\s{\ifx\temp\empty empty\else not empty\fi}
    echo "\s"
}

\formatcommand{}
\formatcommand{ }

\immediate\write255{\formatcommand{}}

\end{document}

(Substituí \write18por \write255para mostrar o comando no terminal porque shell-escape funciona de maneira diferente no LuaTeX, então a execução do comando precisaria de mudanças maiores.)

Usando \immediateassigned, você pode tornar todas as atribuições em um bloco expansíveis:

\documentclass[border=1cm]{standalone}


\begin{document}

\newcommand{\formatcommand}[1]{
  \immediateassigned{%
    \def\temp{#1}
    \def\s{\ifx\temp\empty empty\else not empty\fi}
  }%
    echo "\s"
}

\formatcommand{}
\formatcommand{ }

\immediate\write255{\formatcommand{}}

\end{document}

informação relacionada