Zunächst sei darauf hingewiesen, dass bei LuaTeX 0.85 `\write18` eventuell zukünftig wegfallen wird. Bei `lualatex` wird daher empfohlen, stattdessen entsprechende Lua-Direktiven zu verwenden.
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:
\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?](http://texwelt.de/wissen/fragen/10341/wie-aktiviere-ich-shell-escape-in-meinem-editor)
Üblicherweise wird das verwendet, um irgendwelche externen Programme aufzurufen und dann deren Ergebnisse zu verwenden, beispielsweise:
\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][1]
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:
\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][2]
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 deaktiveren deaktivieren muss oder mit beispielsweise mit `\string` wieder zu einem *normalen* Zeichen machen muss. Obiges Beispiel würde dann zu:
\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
\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 derzeit 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 `lualtex`, `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`](http://www.ctan.org/pkg/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](https://de.wikipedia.org/wiki/Shell_%28Betriebssystem%29)* ü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`](http://www.ctan.org/pkg/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.
[1]: http://texwelt.de/wissen/upfiles/test6_8.png
[2]: http://texwelt.de/wissen/upfiles/test7_5.png