Definieren Sie globale Befehle in der AUX-Datei

Definieren Sie globale Befehle in der AUX-Datei

Ich schreibe ein langes Dokument und um mir das Leben zu erleichtern, definiere ich die von mir verwendeten Mengen gerne als Makros, sodass ich sie bei Änderungen nur an einer Stelle aktualisieren muss. Für mich ist es sinnvoll, diese im Laufe der Arbeit in dem Abschnitt meines Dokuments zu definieren, der für sie am relevantesten ist. Manchmal möchte ich diese Befehle jedoch auch in anderen Kapiteln verwenden, manchmal sogar in vorherigen Kapiteln.

Ich möchte daher ein Makro hinzufügen, das die Definition eines Befehls in die Latex- .auxDateien einfügt, sodass ein Befehl überall verwendet werden kann, sobald er definiert wurde. Bisher habe ich Folgendes:

% 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

Dies fügt Folgendes in die AUX-Datei ein

\providecommand \tester {123}

für ein Kapitel wie dieses:

\chapter{Test chapter}

This is a test chapter!

Tester is \tester{}.

\doccommand{\tester}{123}

Leider funktioniert es nicht. Sogar wenn ich den Befehl im Testkapitel verwende, erhalte ich die Meldung „Undefinierte Steuersequenz“, und dasselbe gilt auch in anderen Kapiteln.

Ursprünglich dachte ich, dass dies möglicherweise etwas mit den Leerzeichen zu tun hat, die in der Datei gelandet sind .aux, aber ich habe sie manuell entfernt und mit einem kompiliert, \includeonly{a_different_chapter}was immer noch den gleichen Fehler erzeugt.

Was gibt?

Aktualisieren:

Dank der Hilfe hier habe ich es zum Laufen gebracht und es in ein kleines Paket geschrieben. Wenn Sie interessiert sind, finden Sie es auf CTAN unterhttps://ctan.org/pkg/globalvals

Antwort1

Ich würde eine andere Strategie verwenden: Verwenden Sie einen Wrapper-Befehl, anstatt Makros direkt zu definieren.

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

Ausgabe des ersten Durchlaufs

Bildbeschreibung hier eingeben

Ausgabe des zweiten Durchlaufs

Bildbeschreibung hier eingeben

Antwort2

Sie könnten schreiben

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

Dadurch wird eine globale Definition durchgeführt, ohne dass der Ersetzungstext erweitert wird. Ich habe eine zusätzliche Direktive hinzugefügt, \gdefdamit der Befehl verwendet werden kann, ohne TeX erneut auszuführen.

Das ist jedoch keine gute Idee: Wenn Sie den Befehl nie vor dem Punkt verwenden, an dem er definiert ist, ist die Definition in der AUX-Datei nutzlos. Wenn Sie den Befehl vor seiner Definition verwenden, erreicht LaTeX nie den Punkt, an dem Sie den AUX-Dateieintrag schreiben.

Sie können den Befehl also erst verwenden, nachdem Sie TeX einmal mit dem definierten, aber nicht verwendeten Befehl ausgeführt haben. Wenn Sie die AUX-Datei jemals löschen, ist Ihr Dokument beschädigt. Wenn Sie jemals nur ein anderes Kapitel einbinden, wird der AUX-Dateieintrag nicht geschrieben, sodass Ihr Dokument beschädigt ist.

Stattdessen könnten Sie eine separate Datei mit den Definitionen erstellen, die Sie in das Präample aufnehmen. Das ist zwar mehr Arbeit, führt aber zu einem wesentlich stabileren Dokument.

Antwort3

Danke @egreg für den cleveren Ansatz. Ich habe seinen Code ganz leicht geändert, um eine Fehlermeldung hinzuzufügen, wenn zwei Definitionen im selben Dokument vorgenommen werden:

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

verwandte Informationen