Umleitungen: Unterschied zwischen den Versionen
Dirk (Diskussion | Beiträge) KKeine Bearbeitungszusammenfassung |
Dirk (Diskussion | Beiträge) KKeine Bearbeitungszusammenfassung |
||
Zeile 88: | Zeile 88: | ||
== Pipes == | == Pipes == | ||
Mittels Pipes wird die Ausgabe eines Programms an ein anderes Programm weitergereicht. Das folgende Beispiel ist eigentlich ein Negativbeispiel, da | 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 | cat file | grep inhalt |
Aktuelle Version vom 4. Januar 2022, 09:47 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 Programmierer 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-/Ausgabeumleitung 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