展開 \write18 中的 \def

展開 \write18 中的 \def

我定義了以下命令:

\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當它們被編寫為 shell 命令時, 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的解決方案,但如果你使用LuaTeX,如果你的問題無法以可擴展的方式編寫,你可以使用另一個技巧:

LuaTeX 有原語\immediateassignment並且\immediateassigned允許可擴展\def

\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 轉義在 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}

相關內容