Am Ende eines Dokuments sollen verschiedene Befehle ausgeführt werden. Hierzu verwende ich \AtEndDocument, wobei es gelegentlich zu Fehlern kommt, was ich am Beispiel eines Seitenlabels demonstrieren möchte. (Ich weiß, dass es hierfür auch das Paket lastpage gibt, aber es soll später mehr als nur das Label am Ende gesetzt werden.)

Folgender Code steht hierzu vor \begin{document}

Open in writeLaTeX
\AtEndDocument{%
% weiterer Code
\label{page:ende}}

Im Dokument wird dann mit \pageref{page:ende} auf die letzte Seite verwiesen.

Nun kommt es aber manchmal dazu, dass , vielleicht abhängig vom Inhalt des Dokuments und der Seitenfüllung, das Dokumentenende nicht richtig erkannt wird und "undefined references" als Fehler ausgegeben wird. In einem Fall, in dem das geschieht, hat mein Dokument zwei Seiten.

Verwende ich im selben Dokument

Open in writeLaTeX
\AtEndDocument{%
% weiterer Code
\label{page:ende}
Hier ist das Dokument zu Ende.}

kommt es zu keinen Fehlern in diesem Sinne, allerdings erhalte ich eine dritte Seite mit der Zeile "Hier ist das Dokument zu Ende." und \pageref{page:ende} liefert den Wert drei. Also passt hier etwas nicht, oder ich scheine was (grundsätzlich) falsch zu machen.

Setze ich im selben Dokument allerdings das Label manuell am Ende, also ohne Verwendung von \AtEndDocument funktioniert die Referenz.

Aktualisierung: Alle Dokumente, in denen dieses Verhalten auftritt, enden mit einer selbstdefinierten Umgebung, an deren Ende \par\vspace{1ex} ausgeführt wird.

Hier mal ein ähnliches Minimalbeispiel:

Open in writeLaTeX
\documentclass{article}

\usepackage{lipsum}

\AtEndDocument{\label{page:ende}}

\newenvironment{aufzaehlung}{%
\begin{itemize}}{\end{itemize}\par\vspace{3ex}}

\begin{document}

\textbf{Insgesamt sind es \pageref{page:ende} Seiten.}

\lipsum[1-9]

\begin{aufzaehlung}
\item Wer?
\item Wie?
\item Was?
\item Warum?
\item Wer nicht fragt bleibt dumm!
\end{aufzaehlung}

\end{document}

Bei \par\vspace{3ex} taucht das Problem auf, bei \par\vspace{2ex} nicht.

gefragt 05 Aug '14, 08:05

feynman's gravatar image

feynman
9671431
Akzeptiert: 100%

bearbeitet 06 Aug '14, 09:07

Ohne Minimalbeispiel lässt sich der eigentliche Fehler (von Deiner anderen Frage) nicht beantworten

(05 Aug '14, 08:13) Clemens

Auch das hier beschriebene Verhalten kann ich nur reproduzieren, wenn die zweite Seite komplett leer ist, also auch gar nicht erstellt wird.

(05 Aug '14, 08:15) Clemens

Verwendest Du irgendwo ein unnötiges \newpage oder \clearpage?

(05 Aug '14, 08:16) Clemens

labels werden beim shipout geschrieben. Wenn nichts auf der Seite ist außer dem label, werden sie nie geschrieben. Versuch z.B. \ref{a}abc\newpage\label{a}. Das lastpage strengt sich ziemlich an, um solche Fälle zu umgehen und den label auch dann zu erzeugen, wenn AtEndDocument auf einer leeren Seite (z.B. nach clearpage um die Floats auszugeben) aufgerufen wird.

(05 Aug '14, 08:24) Ulrike Fischer

Ich werde mal versuchen zwei Minimalbeispiele zu erzeugen. An der Verwendung von \newpage werde ich (im Alltag) vermutlich nicht vorbeikommen.

(05 Aug '14, 08:27) feynman

Aber ganz sicher brauchst Du (auch im Alltag) kein \newpage ganz am Ende?! In meiner Erfahrung braucht man \newpage so gut wie nie, jedenfalls nicht nach \begin{document}. Du weißt, wie man Code im Fließtext eingibt?

(05 Aug '14, 08:30) Clemens

Mit dem Paket etoolbox könnte man versuchen \preto\enddocument{\label{page:ende}}.

(05 Aug '14, 08:38) Henri

Ich denke ich brauche \newpage, da ich bewusst nicht unbedingt immer typographisch korrekte Seiten haben will und auch mal z.B. eine drittel Seite frei lasse. Vielleicht geht das ja auch ohne \newpage, aber davon habe ich ehrlich gesagt keine Ahnung.

(05 Aug '14, 08:39) feynman

Ausserdem wird im LaTeX clsguide daraufhingewiesen, dass \AtBeginDocument und \AtEndDocument keinen Text setzen dürfen. Zumindest dein letztes Beispiel verstößt gegen das Verbot!

(05 Aug '14, 08:39) NobbZ

@Henri Das ändert nichts am Problem, verwendet nur einen anderen Hook

(05 Aug '14, 08:39) Clemens

@feynman Seiten frei zu lassen (z.B. in Arbeitsblättern) ist ja ein anderer Fall, aber auch da braucht man nicht als letztes im Dokument ein \newpage.

(05 Aug '14, 08:47) Clemens

@Nobbz ich hab eine (eher private) Klasse, die gegen dieses „Verbot“ sogar ziemlich dramatisch verstößt ;)

(05 Aug '14, 08:48) Clemens

Vielleicht wurde was missverstanden. Am Ende meiner Dokumente steht selbstverständlich kein \newpage. Trotzdem taucht der beschriebene Sachverhalt manchmal auf.

(05 Aug '14, 08:56) feynman
Ergebnis 5 von 13 Alle anzeigen

Bei der Verwendung von \AtEndDocument für die Erzeugung eines Labels am Ende des Dokuments gibt es mehrere Probleme:

  • Ein späteres \AtEndDocument kann zur Ausgabe weiterer Seiten führen, was laut Doku im Gegensatz zur Ausgabe von Material via \AtBeginDocument auch nicht verboten ist. Damit ist dann das \label nicht mehr auf der letzten Seite.
  • Die Klasse, ein Paket oder irgendwelcher Präambel-Code kann zuvor ein \clearpage via \AtEndDocument eingefügt haben. Damit steht das \label ggf. hinter der letzten Seite. Da \label Code via \write in die aux-Datei schreibt, solche \write-Anweisungen (im Gegensatz zu \immediate\write) aber erst bei der Ausgabe der Seite ausgeführt werden, wird die \label-Anweisung quasi ignoriert, wenn sie nach der Ausgabe der letzten Seite steht. Das führt dann zu einem »undefined reference«-Fehler.
  • Das Dokument könnte zufällig mit der Ausgabe der letzten Seite enden, bevor der \AtEndDocument-Code ausgeführt wird. Auch dann wird die \label-Anweisung kein Label mehr erzeugen.
  • Einige wenige Pakete und Klassen schreiben Code in die aux-Datei, die zu einer weiteren Ausgabe führen. Die aux-Datei wird innerhalb von \end{document} gelesen, nachdem der \AtEndDocument-Code ausgeführt wird. Damit würde die \label-Anweisung ebenfalls zu früh stehen.

Für die ersten drei Probleme gibt es im Paket scrlfile eine sehr einfache Lösung: \BeforeClosingMainAux. Es ist dokumentiert, dass damit gesetzter Code nach dem \AtEndDocument-Code ausgeführt wird und zu keiner weiteren Ausgabe führen darf. Gleichzeitig wird dafür gesorgt, dass die interne LaTeX-Anweisung \protected@write, die von \label verwendet wird, vor der Ausführung des Codes so umdefiniert wird, dass \immediate\write verwendet wird. Damit kann auch \label innerhalb von \BeforeClosingMainAux verwendet werden.

Für das letzte Problem gibt es keine Lösung. Da \label unbedingt in die aux-Datei schreiben muss, kann \label nur verwendet werden, bevor die aux-Datei geschlossen wird. Gelesen wird die aux-Datei aber natürlich erst, nachdem sie geschlossen wurde. Daher kann in der aux-Datei selbst kein \label gesetzt werden. Jeglicher Code in der aux-Datei, der zu einer Ausgabe führt, ist daher als kritisch zu betrachten. Derzeit kenne ich auch nur eine Klasse, die so etwas macht: die Standard-letter-Klasse.

Zusammenfassend sei daher als Lösung:

Open in writeLaTeX
\usepackage{scrlfile}
\BeforeClosingMainAux{%
  \addtocounter{page}{-1}% Da wir uns ja nach der letzten Seite befinden.
  \label{page:ende}%
  \stepcounter{page}% Korrektur (s. o.) wieder rückgängig machen!
}

empfohlen. Näheres zu der Anweisung und der Problematik rund um \AtEndDocument und \clearpage findet sich übrigens in der Erklärung zu \BeforeClosingMainAux und \AfterReadingMainAux in (derzeit) Kapitel 12 der KOMA-Script-Anleitung und natürlich auch im KOMA-Script-Buch.

Das Paket lastpage macht übrigens allerlei Verrenkungen, um das Problem ebenfalls zu lösen, führt aber letztlich nur ein \clearpage aus, bevor es die Label-Informationen per \immediate\write in die aux-Datei schreibt, kann also insbesondere das erste Problem nicht lösen und verschlimmert die Situation für andere Pakete, die Code für die letzte Seite bzw. nach der letzten Seite ausführen wollen, durch das \clearpage noch.

Permanenter link

beantwortet 06 Aug '14, 04:05

Ijon%20Tichy's gravatar image

Ijon Tichy
4.4k618

bearbeitet 06 Aug '14, 06:28

@Ijon Tichy Danke für deine Antwort. Mit Hilfe von \BeforeClosingMainAux{\label{page:ende}} wird das Label nun gesetzt. Allerdings liefert es für die letzte Seite in einem meiner Dokumente den Wert drei, obwohl das Dokument nur zwei Seiten hat.

(06 Aug '14, 05:20) feynman

@feynman Das ist nun einmal das Problem, wenn man kein VM zum Testen geliefert bekommt …

(06 Aug '14, 06:29) Ijon Tichy

Es ist nicht so einfach ein Minimalbeispiel hierzu zu liefern, da es ja scheinbar vom Inhalt abhängt und die Dokumente, bei denen es bei mir auftritt nicht unbedingt hier gelesen werden sollen. Wenn ich den Inhalt aber teilweise nur geringfügig ändere funktioniert wieder alles so wie es soll. Ich habe mich jetzt damit abgefunden für die letzte Seite lastpage und für meine Zähler totcount zu verwenden. Vielen Dank für die Mühe und die ausführliche Antwort, von der ich auf jeden Fall was lernen konnte.

(06 Aug '14, 06:38) feynman

@feynman: Jedenfalls liefert meine Lösung unabhängig vom \vspace am Ende Deines Beispiels das korrekte Ergebnis: Insgesamt sind es 2 Seiten.

(06 Aug '14, 09:59) Ijon Tichy
Deine Antwort auf die Frage (nicht auf andere Antworten)
Knebel-Vorschau

Folge dieser Frage

Per E-Mail:

Wenn Du Dich anmeldest, kannst Du Updates hier abonnieren

Per RSS:

Antworten

Antworten und Kommentare

Aktuelle Buch-Infos

LaTeX Cookbook

LaTeX Beginners Guide

Limitierter Rabatt ebook
50% Coupon code tDRet6Y

Markdown-Grundlagen

  • *kursiv* oder _kursiv_
  • **Fett** oder __Fett__
  • Link:[Text](http://url.com/ "Titel")
  • Bild?![alt Text](/path/img.jpg "Titel")
  • nummerierte Liste: 1. Foo 2. Bar
  • zum Hinzufügen ein Zeilenumbruchs füge einfach zwei Leerzeichen an die Stelle ein, an der die neue Zeile sein soll.
  • grundlegende HTML-Tags werden ebenfalls unterstützt

Zugeordnete Themen:

×19
×1

Frage gestellt: 05 Aug '14, 08:05

Frage wurde angeschaut: 2,002 Mal

Zuletzt aktualisiert: 06 Aug '14, 10:00