
Я определил следующую команду:
\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
определении, т. е. все расширяемые команды расширяются, но выполнение не происходит. Определения макросов (или другие назначения) не расширяются, поэтому \def
s остаются во входном потоке, когда они записываются как команды оболочки.
Решением является использование полностью расширяемого теста для пустого списка токенов, например, следующего \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
которые допускают расширяемые \def
s:
\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}