Hin und wieder liest man in Anleitungen oder Antworten auf Fragen vom dem \write18-Feature. Was ist das? Wie verwendet man es? Auch der Begriff shell-escape wird in diesem Zusammenhang gerne verwendet. Offenbar gibt es eine gleichnamige Programmoption für pdflatex, xelatex und lualatex. Zu deren Aktivierung gibt es auch bereits die Frage: Wie aktiviere ich -shell-escape in meinem Editor?.

gefragt 14 Jan '16, 08:00

saputello's gravatar image

saputello
11.1k174365
Akzeptiert-Rate: 51%


Zunächst sei darauf hingewiesen, dass bei LuaTeX 0.85 \write18 weggefallen ist.

TeX kennt ursprünglich zwar die Möglichkeit, Dateien zu lesen und zu schreiben, aber keine Möglichkeit, externe Programme aufzurufen, um beispielsweise deren Ausgabe wiederum als Eingabe weiter zu verwenden. In den 90er-Jahren des letzten Jahrhunderts wurde das immer mehr zu einem Problem, so dass einer der TeX-Distributoren beschloss, Abhilfe zu schaffen. Er erfand dazu jedoch kein neues Primitiv (aka TeX-Anweisung), sondern erweitere den \write-Mechanismus. Diese Erweiterung ist seit langem in allen TeX-Distributionen bekannt.

Normalerweise wird \write dazu verwendet, um in eine (bereits geöffnete) Datei zu schreiben. Dabei ist das erste Argument von \write die Nummer der Ausgabedatei. Bisher ist die höchste verwendbare Nummer 15. Nicht verwendbare Nummern können (wie alle nicht zum Schreiben geöffneten Nummern) für Ausgaben in die Log-Datei verwendet werden. Üblicherweise werden für die Ausgabe auf Terminal und Log-Datei die Nummern -1 (nur log-Datei) und 17 (log-Datei und Terminal) verwendet. Daher hielt man es für sicher, Nummer 18 für den Aufruf eines externen Programms zu verwenden. Dabei schreibt man quasi in diese Datei den Systemaufruf für das Programm. So erzeugt beispielsweise:

Open in Online-Editor
\documentclass{article}
\usepackage{filecontents}
\begin{filecontents}{Write18Test.tex}
  \documentclass{book}
  \usepackage{mwe}
  \begin{document}
  \blinddocument
  \end{document}
\end{filecontents}
\begin{document}
\immediate\write18{pdflatex Write18Test.tex}
\end{document}

eine Datei Write18Test.pdf mit der book-Klasse. Dazu muss aber die Programmoption -shell-escape beim Aufruf von pdflatex, xelatex oder lualatex gesetzt sein, weil sonst aus Sicherheitsgründen der Aufruf von pdflatex durch die \write18-Anweisung unterbleibt. Wie man das bei den verschiedenen Editoren macht, ist Thema von: Wie aktiviere ich -shell-escape in meinem Editor?

Üblicherweise wird das verwendet, um irgendwelche externen Programme aufzurufen und dann deren Ergebnisse zu verwenden, beispielsweise:

Open in Online-Editor
\documentclass{article}
\usepackage{graphicx}
\usepackage[ngerman]{babel}
\usepackage{filecontents}
\begin{filecontents}{Write18Test.tex}
  \documentclass{scrbook}
  \begin{document}
  \title{Titel}
  \author{Autor}
  \date{\today}
  \maketitle
  \end{document}
\end{filecontents}
\begin{document}
\immediate\write18{pdflatex Write18Test.tex}
Die Standardtitelseite eines Dokuments der Klasse \texttt{book} sieht wie
folgt aus:
\begin{center}
\frame{\includegraphics[width=.5\textwidth]{Write18Test}}
\end{center}
\end{document}

mit dem Ergebnis:

Dokument mit Seite aus einem on-the-fly erzeugten Dokument

Will man die Ausgabe eines Programms als Eingabe wieder in das TeX-Dokument einbinden, bietet es sich an, beim Systemaufruf die Ausgabe in eine temporäre Datei schreiben zu lassen:

Open in Online-Editor
\documentclass{article}
\usepackage{verbatim}
\usepackage[ngerman]{babel}
\begin{document}
\immediate\write18{pdflatex -version > pdflatex.log}
Der Aufruf \verb|pdflatex -version| erzeugt die Ausgabe:
\verbatiminput{pdflatex.log}
\end{document}

So erhält man:

Ausgabe von pdflatex -version

Neuere Implementierungen von pdflatex und xelatex besitzen außerdem eine Pipe-Erweiterung, die es erlaubt, die Ausgabe eines Programms direkt per \input oder \openin zu lesen. Dazu wird der Programmaufruf mit einem Pipe-Symbol | begonnen und in " eingeschlossen. Bei Verwendung von babel mit einer Deutschen Spracheinstellung, kollidiert dies allerdings mit dem shorthand ", das man entweder vorübergehend deaktivieren muss oder mit beispielsweise mit \string wieder zu einem normalen Zeichen machen muss. Obiges Beispiel würde dann zu:

Open in Online-Editor
\documentclass{article}
\usepackage{verbatim}
\usepackage[ngerman]{babel}
\begin{document}
Der Aufruf \verb|pdflatex -version| erzeugt die Ausgabe:
\verbatiminput{\string"| pdflatex -version\string"}
\end{document}

Dieses Beispiel funktioniert nicht mit lualatex, da lualatex bis Version 0.85 in dem Fall nicht pdflatex -version, sondern pdflatex -version.tex aufruft. Zwar erhält man mit

Open in Online-Editor
\documentclass{article}
\usepackage{fontspec}
\usepackage{verbatim}
\usepackage[ngerman]{babel}
\begin{document}
Der Aufruf \verb|pdflatex -version| erzeugt die Ausgabe:
\verbatiminput{\string"| pdflatex -version \string"}
\end{document}

hier auch mit lualatex vor Version 0.85 das gewünschte Ergebnis, das funktioniert aber nur, weil in diesem Fall pdflatex -version .tex aufgerufen wird und pdflatex das zusätzliche Argument .tex bei Option -version ignoriert. In anderen Fällen stört ein solches zusätzliches Argument aber. Für Lösungen, die auch mit lualatex funktionieren sollen, konnte und kann daher die Verwendung dieser Pipe-Erweiterung nicht allgemein empfohlen werden.

Ein Problem der \write18-Möglichkeit und auch der Pipe-Erweiterung ist, dass Dokumente damit sehr schnell abhängig vom Betriebssystem werden. Während obige Beispiele noch sowohl unter Windows als auch unter Linux als auch unter OS X funktionieren, wird es beispielsweise bei der Ausgabe des aktuellen Verzeichnisinhalts schon schwierig. So würde zwar \immediate\write18{dir >verzeichnisinhalt.txt} unter Windows funktionieren, in einer *nix-Shell aber üblicherweise nicht. Daher müsste es unter Linux oder OS X stattdessen \immediate\write18{ls >verzeichnisinhalt.txt} lauten [Fußnote: Einige Linux-Distributionen definieren dir als Standard-Alias für ls -l.]. Weiter noch: Die Ausgaben wären im Beispiel für die beiden Aufrufe auch unterschiedlich. Teilweise ist auch bei den gleichen externen Programmen unter verschiedenen System die Syntax für den Aufruf unterschiedlich.

Übrigens gibt es je nach Maschine, also je nach Verwendung von lualatex, pdflatex oder xelatex unterschiedliche Möglichkeiten abzufragen, ob Option -shell-escape gesetzt ist, also \write18 tatsächlich einen Programmaufruf tätigt. Diese unterschiedlichen Abfragemöglichkeiten werden vom Paket pdftexcmds für pdflatex und lualatex etwas vereinheitlicht.

Der Name shell-escape kommt daher, dass die Ausführung von externen Programmen über einen Systemaufruf erfolgt, der die Ausführung der sogenannten System-Shell überlässt. Bei LuaTeX steuert die entsprechende Optionen nicht nur, was \write18 darf, sondern auch Programmaufrufe über Lua-Direktiven.

Wegen der Problematik, dass bei LuaTeX seit Version 0.85 \write18 nicht mehr für Programmaufrufe verwendet werden kann, hat das LaTeX-Team das Paket shellesc veröffentlicht. Dieses bietet die Anweisungen \ShellEscape und \DelayedShellEscape. Ersteres entspricht \immediate\write18, letzteres \write18. Bei Verwendung von lualatex werden die Anweisungen allerdings über die Lua-Funktion os.execute realisiert. Das Paket prüft außerdem, ob Systemaufrufe überhaupt aktiviert sind und gibt ggf. eine Warnung »Shell escape disabled« aus, falls Systemaufrufe generell deaktiviert sind. Anderenfalls wird je nach Einstellung entweder die Information »Restricted shell escape enabled« oder »Unrestricted shell escape enabled« in die log-Datei geschrieben. Letzteres wird für allgemeine Systemaufrufe benötigt.

Permanenter link

beantwortet 14 Jan '16, 09:13

saputello's gravatar image

saputello
11.1k174365
Akzeptiert-Rate: 51%

bearbeitet 07 Jun '16, 15:23

Man kann die Standardausgabe eines Programms auch direkt mit z.B. \input{"| pdflatex -version"} einbinden. So spart sich die extra Datei. Ist aber eine e-TeX extension.

(20 Jan '16, 18:31) Henri

@Henri: Ja, diese (neuere) Entwicklung existiert. Eigentlich wollte ich sie aber weglassen, weil sie für das generelle Verständnis, was \write18 ist, nicht notwendig ist und auch eher selten verwendet wird. Mich hat daran auch schon immer gestört, dass aus meiner Sicht eine Pipe am Anfang bedeutet, dass in einen Prozess geschrieben und nicht aus ihm gelesen wird. Außerdem funktioniert das bei lualatex nach meinen Versuchen eher schlecht (siehe erweiterte Antwort).

(20 Jan '16, 19:01) saputello
Deine Antwort
Vorschau umschalten

Folgen dieser Frage

Per E-Mail:

Wenn sie sich anmelden, kommen Sie für alle Updates hier in Frage

Per RSS:

Antworten

Antworten und Kommentare

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ügen Sie einfach zwei Leerzeichen an die Stelle an der die neue Linie sein soll.
  • grundlegende HTML-Tags werden ebenfalls unterstützt

Frage-Themen:

×117
×3
×1
×1

gestellte Frage: 14 Jan '16, 08:00

Frage wurde gesehen: 19,693 Mal

zuletzt geändert: 07 Jun '16, 15:23