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