# Expand \def in \write18

I have defined the following command:

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


This works correctly:

\formatcommand{}
\formatcommand{ }


However, when using the above command inside \write18,

\immediate\write18{\formatcommand{}}


the \defs seem to not be expanding, since I'm getting \def is not an executable..., meaning that \write18 sent the body of \formatcommand{} without expanding it to the command line. How can this be fixed?

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


When TeX writes the contents of a \write command, it expands all material similarly to what happens on an \edef defintion, i.e. all expandable commands are expanded but no execution happens. Macro definitions (or other assignments) are not expandable, so the \defs remain in the input stream when they are written as shell commands.

The solution is to use a fully-expandable test for an empty token list, like the following \ifempty macro:

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


Generally I recommend siracusa'a solution, but if you LuaTeX there is another trick which you can use if your problem can't be written in an expandable manner:

LuaTeX has primitives \immediateassignment and \immediateassigned which allow expandable \defs:

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


(I replaced \write18 with \write255 to show the command on the terminal because shell-escape works differently in LuaTeX, so executing the command would have needed bigger changes.)

Using \immediateassigned, you can make all assignments in a block expandable:

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