在 aux 文件中定义全局命令

在 aux 文件中定义全局命令

我正在写一篇很长的文档,为了让我的生活更轻松,我喜欢将我使用的数量定义为宏,这样当它们发生变化时,我只需在一个地方更新它们。对我来说,在文档中与它们最相关的部分中定义这些命令是有意义的。然而,有时我想在其他章节中使用这些命令,有时甚至在之前的章节中。

因此,我想添加一个宏,将命令的定义吐出到 latex.aux文件中,这样一旦定义了命令,就可以在任何地方使用。到目前为止,我得到了以下内容:

% Make a command which defines a macro with \providecommand but in the aux file,
% so it's accessible to all other chapters
\makeatletter
\newcommand{\doccommand}[2]{%
\protected@write\@auxout{}{\protect\providecommand\protect#1{#2}}%
}
\makeatother

这会将以下内容放入 aux 文件中

\providecommand \tester {123}

对于这样的章节:

\chapter{Test chapter}

This is a test chapter!

Tester is \tester{}.

\doccommand{\tester}{123}

不幸的是,它不起作用。即使在测试章节中使用该命令,也会给出“未定义的控制序列”的结果,其他章节也一样。

最初我认为这可能与文件中的空格有关.aux,但我手动删除了它们并用\includeonly{a_different_chapter}仍然出现相同错误的方法进行编译。

是什么赋予了?

更新:

感谢大家的帮助,我让它工作起来,并把它写成了一个小包。如果你感兴趣,你可以在 CTAN 上找到它https://ctan.org/pkg/globalvals

答案1

我会使用不同的策略:使用包装命令,而不是直接定义宏。

\documentclass{article}

\makeatletter
\newcommand{\usevalue}[1]{%
  \ifcsname usevalue@#1\endcsname
    \csname usevalue@#1\endcsname
  \else
    ??%
  \fi
}
\newcommand{\definevalue}[2]{%
  \write\@auxout{%
    \unexpanded{\global\@namedef{usevalue@#1}{#2}}%
  }
}
\makeatother

\begin{document}

Something with \usevalue{tester}.

Something else.

Now we can define \texttt{tester} and use again it: \usevalue{tester}.

\definevalue{tester}{42}

\end{document}

第一次运行的输出

在此处输入图片描述

第二次运行的输出

在此处输入图片描述

答案2

你可以写

\makeatletter
\newcommand{\doccommand}[2]{%
  \immediate\write\@auxout{\gdef\noexpand#1{\unexpanded{#2}}}%
  \gdef#1{#2}%
}
\makeatother

这将进行全局定义,而不扩展替换文本。我添加了一个额外的指令,\gdef以便可以在不重新运行 TeX 的情况下使用该命令。

但这不是一个好主意:如果你在命令定义之前从未使用过它,那么在辅助文件中定义它是无用的。如果你在定义命令之前使用该命令,LaTeX 就永远不会到达你编写辅助文件条目的那个点。

因此,您只能在运行 TeX 一次且命令已定义但未使用后才能使用该命令。如果您删除了辅助文件,您的文档就会损坏。如果您只包含不同的章节,辅助文件条目将不会被写入,因此您的文档就会损坏。

相反,您可以创建一个单独的文件,其中包含您在前言中包含的定义。这需要更多工作,但会产生更稳定的文档。

答案3

感谢@egreg的聪明方法。我稍微修改了他的代码,如果在同一文档中有两个定义,则添加一条错误消息:

\documentclass{article}    

\usepackage{siunitx}

\makeatletter
\newcommand{\useVal}[1]{%
  \ifcsname useVal@#1\endcsname
    \csname useVal@#1\endcsname
  \else
    ??%
  \fi
}
\newcommand{\defVal}[2]{%
\ifcsname useVal@#1@defined\endcsname
    \PackageError{useVal}{Value "#1" already defined}{}
\else
  \write\@auxout{%
    \unexpanded{\global\@namedef{useVal@#1}{#2}}%
  }
  \global\@namedef{useVal@#1@defined}{}
\fi
}
\makeatother

\begin{document}

Testval is \useVal{testVal}.

Now defining testval...

\defVal{testVal}{\SI{123}{\meter}}

Now it's \useVal{testVal}. 

% This would throw an error:
% \defVal{testVal}{Not this please!}

\end{document}

相关内容