In vergangenen Teilen habe ich von Piping schon öfters Gebrauch gemacht. Zeit, es mal zu erklären.
1 | Einführung |
---|---|
2 | Der bash Prompt |
3 | key bindings |
4 | Der Startvorgang |
5 | Environment Variablen |
6 | builtin commands |
7 | Arbeiten mit Dateien |
8 | nano |
9 | bash Scripting |
10 | Variablen |
11 | Verzweigungen (if) |
12 | Schleifen |
13 | Kommandozeilenparameter |
14 | exit Codes bash Tutorial Teil 14 |
15 | von der Idee zum Script |
16 | grep |
17 | Piping und Redirection |
18 | tee |
Eingabe- und AusgabeKanäle
Die bash hat drei verschiedene Kanäle ( Streams), die sich für die Eingabe- und Ausgabe von Daten zuständig sind.
Da ist zunächst stdin. Dies ist der Regel die Tastatur
Die Standardausgabe wird über stdout abgewickelt. Dieser Kanal ist meistens mit der Console verbunden. Hier landet alles, was ein Programm ausgibt, abgesehen von Fehlermeldungen.
stderr arbeitet ähnlich wie stdout, allerdings sollen hier nur Fehlermeldungen erscheinen. Üblicherweise ist dieser Kanal auch mit der Console verbunden. Könnte allerdings auch z.B. in eine Datei oder auf den Drucker umgelenkt werden.
Redirection
Das Umlenken (Redirection) von Kanälen habe ich schon früher benutzt.Der häufigste Anwendungsfall ist wohl, die Ausgabe eines Programms in einer Datei zu speichern, um sie für die spätere Auswertung zur Verfügung zu haben. Das probieren wir direkt mal praktisch aus. Um stdout in eine Datei umzulenken, benutzt du das „größer als“ Zeichen gefolgt vom Dateinamen.
ls -l / > ls.txt
Dabei wird eine neue Datei ls.txt angelegt und alles, was das ls Kommando ausgibt, in diese Datei hineingeschrieben. Das birgt eine gewisse Gefahr mit sich, da eine bereits vorhandene Datei überschrieben wird. In ls.txt findest du genau das wieder, was ls ausgegeben hat, während auf der Console nichts zu sehen ist.
cat ls.txt
Es gibt auch die Möglichkeit, den ausgegebenen Text an eine bestehende Datei anzuhängen. Dazu benutzt zwei „größer als“ Zeichen direkt hintereinander schreibst.
for i in {1..3}; do
ls -al >> ls.txt
done
In diesem Fall wird ls.txt nicht bei jedem Aufruf von ls neu angelegt sondern in jedem Schleifendurchlauf wird die Ausgabe von ls an die bestehende Datei hinten angehängt.
Unerwünschten Output umleiten
Wenn ein Kommando, das du in deinem Script verwendest, Ausgaben nach stdout schreibt, die du nicht sehen möchtest, kannst du diese loswerden, in dem du du stdout nach /dev/null
umleitest. Das Null-Device ist ein besonders File, dass alles, was du hinleitest, einfach verwirft.
ls -l / > /dev/null
Dieser Aufruf von ls wird nichts ausgeben, da die gesamte Ausgabe in /dev/null
verschwindet.
Jetzt achte mal darauf, was passiert, wenn ich ls auf ein nicht existierendes Verzeichnis aufrufe:
ls -l ~/foo > ls.txt
Du erkennst, dass die Fehlermeldung auf der Console erscheint. Die Ausgabedatei ist leer, da ls wegen des Fehlers nichts in stdout
geschrieben hat. Die Fehlermeldung wird nach stderr
geschrieben. Da der Kanal nicht umgeleitet wird, steht die Fehlermeldung nicht in der Datei.
Es gibt aber eine Möglichkeit, stderr
nach stdout
um zu leiten.
ls -l ~/foo 2>ls.txt >ls.txt
Die Fehlermeldung steht jetzt in ls.txt.Die 2 bezeichnet die Kanalnummer: stdin
= 0, stdout
= 1, stderr
= 2
Du kannst auch stderr
nach stdout
umleiten.
ls -l ~/foo 2>&1
Beim Ausführen wirst du keinen Unterschied erkennen, da stderr per Voreinstellung auch auf die Console ausgibt.
Piping
Eine Pipe (dt. Röhre) leitet Ausgabedaten des einen Programms von stdout nach stdin eines anderen Programms weiter. Ich habe dieses Verfahren schon häufig benutzt, da es eins der wichtigsten Features einer Shell ist. Zum Piping benutzt du den „senkrechten Strich“ (AltGr > auf einem Standard PC Keyboard). Ich nenne den senkrechten Strich inzwischen eigentlich fast nur noch Pipe.
Die Datei ls.txt kannst du dir mit cat anzeigen lassen.
cat ls.txt
Das ist nicht Neues. Aber den Umweg über die Datei kannst du dir sparen mit einer Pipe.
ls -l / | cat
Was passiert hier? Das ls
Kommando wird ausgeführt, doch statt nach stdout zu schreiben, landet das Directorylisting durch die Pipe direkt in stdin von cat
, dass die Daten nach stdout ausgibt. Das macht in diesem Fall natürlich gar keinen Sinn. Sehr viel nützlicher ist es, wenn das Kommando, in das hinein gepiped wird, etwas mit den empfangenen Daten tut, wie z.B. grep oder sort
.
So kannst du mit grep in langen Verzeichnislisten einfach die Zeile herausfiltern, die dich interessiert.
ls -l / | grep boot
Die Ausgabe von ls wird nach grep gepiped, dass nur noch Zeilen durchlässt, die den String boot enthalten.
Übrigens: Ob du das Pipesymbol mit Leerzeichen umgibst, ist unwichtig, ich mache das hier nur zur besseren Lesbarkeit.
Du kannst den Output von grep auch direkt in das nächste Kommando pipen und eine lange Kette von Pipes aufbauen.
Im nächsten Teil werden wir das Piping mit dem tee Kommando weiterführen.