Expandir \def en \write18

Expandir \def en \write18

He definido el siguiente comando:

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

Esto funciona correctamente:

\formatcommand{}
\formatcommand{ }

muestra

Sin embargo, cuando se utiliza el comando anterior en el interior \write18,

\immediate\write18{\formatcommand{}}

los \defs parecen no expandirse, ya que estoy obteniendo \def is not an executable..., lo que significa que \write18envió el cuerpo de \formatcommand{}sin expandirlo a la línea de comando. ¿Cómo se puede arreglar esto?

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}

Respuesta1

Cuando TeX escribe el contenido de un \writecomando, expande todo el material de manera similar a lo que sucede en una \edefdefinición, es decir, todos los comandos expandibles se expanden pero no ocurre ninguna ejecución. Las definiciones de macros (u otras asignaciones) no se pueden expandir, por lo que los \defmensajes de correo electrónico permanecen en el flujo de entrada cuando se escriben como comandos de shell.

La solución es utilizar una prueba completamente expandible para una lista de tokens vacía, como la siguiente \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}"
}

Respuesta2

Generalmente recomiendo la solución siracusa, pero si usas LuaTeX hay otro truco que puedes usar si tu problema no se puede escribir de manera expandible:

LuaTeX tiene primitivas \immediateassignmenty \immediateassignedque permiten \defs expandibles:

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

(Lo reemplacé \write18con \write255para mostrar el comando en la terminal porque shell-escape funciona de manera diferente en LuaTeX, por lo que ejecutar el comando habría necesitado cambios mayores).

Usando \immediateassigned, puedes hacer que todas las asignaciones en un bloque sean expandibles:

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

información relacionada