Развернуть \def в \write18

Развернуть \def в \write18

Я определил следующую команду:

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

Это работает правильно:

\formatcommand{}
\formatcommand{ }

образец

Однако при использовании указанной выше команды внутри \write18,

\immediate\write18{\formatcommand{}}

s \def, похоже, не расширяется, так как я получаю \def is not an executable..., что означает, что \write18отправил тело \formatcommand{}без его расширения в командную строку. Как это можно исправить?

МВЭ

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

решение1

Когда TeX записывает содержимое команды \write, он расширяет весь материал аналогично тому, что происходит в \edefопределении, т. е. все расширяемые команды расширяются, но выполнение не происходит. Определения макросов (или другие назначения) не расширяются, поэтому \defs остаются во входном потоке, когда они записываются как команды оболочки.

Решением является использование полностью расширяемого теста для пустого списка токенов, например, следующего \ifemptyмакроса:

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

решение2

Обычно я рекомендую решение siracusa'a, но если вы используете LuaTeX, есть еще один прием, который вы можете использовать, если вашу задачу нельзя записать в расширяемой форме:

LuaTeX имеет примитивы \immediateassignment, \immediateassignedкоторые допускают расширяемые \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}

(Я заменил \write18на \write255, чтобы отобразить команду на терминале, поскольку shell-escape работает по-другому в LuaTeX, поэтому выполнение команды потребовало бы более существенных изменений.)

Используя \immediateassigned, вы можете сделать все назначения в блоке расширяемыми:

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

Связанный контент