Umleitungen: Unterschied zwischen den Versionen
Boenki (Diskussion | Beiträge) K typos |
Dirk (Diskussion | Beiträge) K →Bezeichnungen: es muss natürlich STDERR heißen |
||
Zeile 18: | Zeile 18: | ||
|STDOUT || Standardausgabe-Kanal || <code>1</code> oder <code>&1</code> | |STDOUT || Standardausgabe-Kanal || <code>1</code> oder <code>&1</code> | ||
|- | |- | ||
| | |STDERR || Standard-Fehlerkanal || <code>2</code> oder <code>&2</code> | ||
|} | |} | ||
Version vom 3. Juli 2012, 11:57 Uhr
Eine der Stärken von Linux ist, dass Ein- und Ausgabe von Programmen umgeleitet werden können. Es gibt zwei wichtige Ausgabeleitungen (Kanäle genannt), dies sind STDERR, auf das alle Fehlermeldungen ausgegeben werden und STDOUT, auf das alle normalen Programm-Ausgaben ausgegeben werden. Zusätzlich gibt es noch den Standardeingabe-Kanal STDIN.
Bezeichnungen
Je nach Position an der ein Kanal angesprochen wird, hat er unterschiedliche Bezeichnungen, zudem werden die Kanäle je nach Position unterschiedlich referenziert.
Kanal | Bezeichnung | Schreibweise |
---|---|---|
STDIN | Eingabeumleitung | < oder <<
|
STDIN | Standardeingabe | -
|
STDOUT | Ausgabeumleitung | > oder >>
|
STDOUT | Standardausgabe | -
|
STDOUT | Standardausgabe-Kanal | 1 oder &1
|
STDERR | Standard-Fehlerkanal | 2 oder &2
|
In diesem Artikel werden der Standardeingabe-Kanal und der Standardausgabe-Kanal, so wie der Standard-Fehlerkanal immer als STDIN, STDOUT und STDERR bezeichnet.
Ausgabeumleitung
Prinzipiell können alle Ausgaben von Programmen entweder in eine Datei geschrieben, oder als Eingabe für weitere Programme verwendet werden. Die Angabe zur Umleitung kann zwar theoretisch an jeder Stelle eines Befehls gemacht werden, aus Gründen der Übersicht und der Logik sollte man eine Ausgabeumleitung aber nicht vor einer Eingabeumleitung oder dem eigentlichen Befehl definieren.
Der einfachste Fall einer Ausgabeumleitung ist das Umleiten von STDOUT in eine Textdatei, um so zum Beispiel eine Dateiliste zu erhalten.
ls -al > output
Dies schreibt die Namen der Dateien und Verzeichnisse im aktuellen Verzeichnis in die Datei „output“. Wenn die Datei noch nicht existiert, wird sie angelegt. Falls sie bereits existiert, wird sie überschrieben. Wenn man möchte, dass die Ausgabe an die Datei angehängt wird, benutzt man „>>“, anstatt „>“
ls -al >> output >> output ls -al
Die zweite Zeile bewirkt das Selbe wie die erste Zeile, soll hier aber nur als Beispiel dafür dienen, dass es relativ irrelevant ist, an welcher Stelle eine Umleitung definiert wird (hier vor dem eigentlich umzuleitenden Befehl).
Die einfache Umleitung ohne Angabe des Kanals leitet immer STDOUT entsprechend um. Fehlermeldungen, die nach STDERR geschrieben werden, werden damit nicht umgeleitet. Es ist natürlich möglich, diese Fehlermeldungen auch umzuleiten
command 2>> error.log
Dies schreibt alle Fehlermeldungen des Programms „command“ in die Datei „error.log“, wobei die Datei nicht überschrieben, sondern die Ausgabe immer an die Datei angehängt wird. Will man jetzt auch noch die Standard-Ausgabe umleiten, zum Beispiel nach /dev/null, weil das Programm als Cronjob läuft, und die Ausgabe unwichtig ist, geht dies mit folgendem Aufruf
command > /dev/null 2>> error.log
Dies schreibt STDOUT nach /dev/null, und STDERR in die Datei „error.log“. Es besteht auch die Möglichkeit, Kanäle „ineinanderzuleiten“. Dies kann nützlich sein, wenn man STDERR und STDOUT an die selbe Stelle umleiten möchte.
command 2>&1> /dev/null command > /dev/null 2>&1
Dies leitet STDERR nach STDOUT (STDOUT wird hier mittels „&1“ referenziert. STDERR würde an dieser Stelle analog dazu mit „&2“ referenziert werden) um. STDOUT wird nach „/dev/null“ umgeleitet. Das Resultat ist, dass weder Standard-Meldungen noch Fehlermeldungen von „command“ ausgegeben werden.
Die zweite Zeile ist eine gängige, alternative Schreibweise dieses Aufrufs. Durch „> /dev/null“ wird die STDOUT nach „/dev/null“ geleitet, durch „2>&1“ wird STDERR nach STDOUT geleitet (das ja nach „/dev/null“ geleitet wird).
Alternativ kann man die Ausgabe auch in eine Datei umleiten. Es besteht ebenfalls die Möglichkeit, die zweite Umleitung ganz weg zu lassen.
command 2>&1
Dies leitet STDERR auf STDOUT um. Damit kann man nun mittels Pipe (siehe unten) die Standard-Ausgabe und die Fehlermeldungen in anderen Programmen als Eingabe benutzen.
Eingabeumleitung
Genau so, wie man Ausgaben umleiten kann, kann man auch Eingaben umleiten. Genauer gesagt kann man andere Eingabekanäle als STDIN verwenden, bzw. auf andere Art über STDIN etwas an ein Programm senden.
command < input
Dies leitet den Inhalt der Datei „input“ an das Programm „command“ weiter. Wie dieses Programm damit umgeht, ist dem Programmier des Programms überlassen. Wenn ein Programm keine derartigen Umleitungen annimmt, passiert für gewöhnlich gar nichts. Eine weitere Methode ist die Umleitung mittels „<<EOF“.
command <<EOF > Zeile 1 > Zeile 2 > Zeile 3 > Zeile N > EOF
Dies übergibt dem Programm „command“ die Zeilen 1 bis N in dieser Reihenfolge, jeweils als eigenständige Eingabe. Beim Schlüsselwort „EOF“ wird die Eingabeumleitung beendet. Statt „EOF“ kann man nahezu beliebige Schlüsselwörter verwenden, „EOF“ hat sich aber eingebürgert. Eine konkrete Anwendung könnte zum Beispiel ein Backup einer MySQL-Datenbank sein.
mysql -uUSER -pPASSWORD <<EOF flush tables with read lock; system lvcreate -l100%FREE -s -n dbbackup /dev/vgmysql/mysql; unlock tables; EOF
Dieser Aufruf sperrt die Datenbank für Schreibzugriffe, erstellt durch einen MySQL-internen Systemaufruf einen LVM-Snapshot an angegebener Position, und gibt die Tabellen wieder frei. Mittels weiterer Programme kann nun mit dem Snapshot gearbeitet werden (Backup erstellen, etc.), ohne, dass die eigentliche Tabelle beeinflusst wird.
Per Eingabeumleitung werden hier drei Befehle an den MySQL-client gesendet. Dieser interpretiert die Befehle so, als wenn sie direkt eingegeben worden wären.
Pipes
Mittels Pipes wird die Ausgabe eines Programms an ein anderes Programm weitergereicht. Das folgende Beispiel ist eigentlich ein Negativbeispiel, da grep bereits selbst über so eine Funktionalität verfügt, wird allerdings immer wieder gern hergenommen, um die Funktionsweise von Pipes zu demonstrieren, da es einfach und gut nachvollziehbar ist.
cat file | grep inhalt
Durch „cat file“ wird der Inhalt der Datei „file“ ausgegeben. Die Ausgabe wird an „grep“ weitergeleitet, mittels dem die Ausgabe von „cat“, die nun Eingabe von „grep“ geworden ist, nach dem Wort „inhalt“ durchsucht wird. Es werden nun nur Zeilen ausgegeben, in denen „inhalt“ steht.
Nur der Vollständigkeit halber, dies geht auch ohne cat:
grep inhalt file
Einige Programme behandeln STDIN und STDOUT in Verbindung mit Pipes ein wenig anders. Generell muss man hier die Manpage des jeweiligen Programms lesen, an welcher Stelle STDIN und STDOUT berücksichtigt werden, dann allerdings werden beide durch ein Minus-Zeichen angesprochen.
Ein konkretes Beispiel könnte das Aktualisieren eines Wallpapers sein. Das Wallpaper wird automatisch im Internet regelmäßig durch ein neues Wallpaper an selber Position ersetzt. Anstatt nun manuell jedes Mal das Wallpaper herunterzuladen und manuell jedes Mal einzustellen, kann man dies mittels wget und „display“ aus dem ImageMagick-Paket machen.
wget http://example.com/zufallswallpaper.png -O - | display -window root -
Hier wird durch wget das Wallpaper heruntergeladen. Anstatt das Wallpaper standardmäßig abzuspeichern wird es mittels „-O“ unter einer anderen Bezeichnung gespeichert, in diesem Fall ist dies die Standard-Ausgabe. Die Meldungen die wget sonst noch ausgibt, werden dabei nicht mit ausgegeben, sondern lediglich die heruntergeladene Datei.
Nach der Pipe wird „display“ aufgerufen, durch „-window root“ wird definiert, dass es das Bild auf dem Root-Fenster anzeigen soll, dies ist der Desktop. Durch „-“ wird hier die Standard-Eingabe referenziert. In der Standard-Eingabe befindet sich das, was wget davor in seine Standard-Ausgabe geschrieben hat.
FIFO-Pipes
FIFO steht für „First In First Out“ (sinngemäß „Was zuerst eingegeben wird, wird zuerst wieder ausgegeben“). FIFO-Pipes können als Zwischenschritt genutzt werden, wenn ein Programm nicht mittels Ein-/Ausgabeiumleitung oder herkömmlicher Pipes verwendet werden kann, oder die Verwendung von Pipes aufgrund technischer Umstände nicht möglich ist.
Übertragene Darstellung
FIFO-Pipes kann man sich am besten als ein Rohr vorstellen. Auf beiden Seiten dieses Rohrs befinden sich Deckel. Wenn ein Programm nun auf einen FIFO-Pipe zugreift, wird der Deckel geöffnet, und das Programm schiebt die Ausgabe in das Rohr, bis die Ausgabe auf der anderen Seite an den Deckel stößt, dann wartet es.
Das Rohr bleibt dort so lange verschlossen, bis ein zweites Programm auf die FIFO-Pipe zugreift. Das zweite Programm öffnet den Deckel, und nimmt die Ausgabe des ersten Programms in der Reihenfolge in Empfang, wie sie das erste Programm in das Rohr geschoben hat. Die FIFO-Pipe ist nun offen.
Das Programm, das die Daten in Empfang nimmt, macht dies so lange, wie der „Deckel“ des eingebenden Programms geöffnet ist. Der Deckel dieses Programms schließt sich, wenn es alle Daten in das Rohr geschoben hat. Die FIFO-Pipe ist dann geschlossen. Das empfangende Programm registriert dies, und schließt die seinen Deckel ebenfalls.
Der Vergleich hinkt ein wenig, da alles in dem „Rohr“ in praktisch Echtzeit geschieht, und auch nichts in das Rohr „hineingeschoben“ wird, sondern das eine Programm einfach so lange mit der Ausgabe wartet, bis das andere Programm die Eingabe anfordert.
Verwendung
Wenn man eine FIFO-Pipe verwenden will, muss diese zuerst angelegt werden. Danach kann man sie ganz normal als Ausgabeumleitungs-Ziel verwenden.
mkfifo fifopipe ls -l / > fifopipe & cat fifopipe
Diese (eigentlich unnütze und nur der Demonstration dienende) Verwendung der FIFO-Pipe macht folgendes: Zuerst wird die FIFO-Pipe angelegt, dann wird die Ausgabe von „ls -l /“ an diese FIFO-Pipe gesendet. Nun wird mittels „cat“ die Pipe ausgegeben. Man sieht nun die Ausgabe von „ls -l /“.
Wenn man nun noch mal mittels „cat“ die Inhalte der FIFO-Pipe ausgeben will, bekommt man nichts zurück, da der „Deckel“ auf der „anderen Seite“ ja nicht „geöffnet“ ist. Erst wenn man „auf der anderen Seite“ (zum Beispiel durch ein weiteres „ls -l /“, das man in die FIFO-Pipe umleitet) wieder etwas „in das Rohr schiebt“, erhält man eine Ausgabe.
FIFO-Dateien benutzen zum Weiterleiten der Inhalte Dateisystemfunktionen, normale Pipes benutzen Kernel-interne Puffer, wodurch diese Methode schneller ist. FIFO-Pipes können über Prozessgrenzen hinweg verwendet werden, wohingegen Pipes nur innerhalb des selben Elterprozesses verwendet werden können.
Siehe auch
- Manpage „stdio“ (vor allem für Programmierer interessant)
- bash