Mit wenigen Handgriffen leiten Sie auf der Kommandozeile Ein- und Ausgaben von Befehlen um und kombinieren Kommandos. Wir stellen die benötigten Bash-Operatoren vor und zeigen, wie Sie mit dem Programm tee noch einen Zwischenschritt einlegen.
Zu Befehl
Auch wenn sich viele Dinge bequem über grafische Oberflächen wie KDE oder GNOME regeln lassen – wer sein Linux-System richtig ausreizen möchte, kommt um die Kommandozeile nicht herum. Abgesehen davon gibt es auch sonst viele Situationen, in denen es gut ist, sich im Befehlszeilendschungel ein wenig auszukennen.
“Zu Befehl” stellt seit Jahren regelmäßig Shell-Kommandos vor und verrät Tricks und Kniffe, mit denen Sie Programme geschickt kombinieren. Dabei kommen immer wieder ganz selbstverständlich Umleitungsoperatoren zum Einsatz. Was genau dahinter steckt und was Sie alles umleiten können, erfahren Sie in dieser “Zu Befehl”-Folge.
Drei Kanäle
Für die Ein- und Ausgaben von Programmen gibt es drei “Standardkanäle”: Laufende Programme erwarten ihren Input von der Standardeingabe (stdin), z. B. über die Tastatur. Normale Ausgaben schicken Programme auf die Standardausgabe (stdout), das ist in der Regel das Terminal-Fenster, in dem Sie das Programm gestartet haben. Zusätzlich gibt es eine Standardfehlerausgabe (stderr), die meist am gleichen Ort erscheint: Hier finden Sie eventuelle Fehlermeldungen des Befehls mit Hinweisen, die zur Problemlösung führen können. Zur Kennzeichnung der drei Kanäle dienen so genannte File Descriptors, die Standardkanäle werden hier einfach durchgezählt. stdin hat die Nummer 0, stdout die 1 und stderr die 2.
Wie diese drei Kanäle zusammenarbeiten, erkennen Sie schön an einem einfachen Beispiel:
huhn@asteroid:~$ /sbin/fsck /dev/hda7 Do you want to run this program?[N/Yes] : Yes reiserfsck: Cannot not open filesystem on "/dev/hda7" Warning… fsck.reiserfs for device /dev/hda7 exited with signal 6.
Im Terminal-Fenster erscheinen die normalen Ausgaben des Programmes, z. B. die Frage, ob das Programm wirklich ausgeführt werden soll. Die Antwort wird aus der Standardeingabe gelesen, das ist hier die Tastatur. Nach dem Bestätigen folgt eine Fehlermeldung, da die nötigen Root-Rechte fehlen. Diese Fehlermeldung gibt reiserfsck über die Standardfehlerausgabe aus.
Ein übersichtlicheres Beispiel ist der folgende grep-Aufruf:
huhn@asteroid:~$ grep bla * datei1:bla datei2:bla bla grep: verz: Is a directory
Das Kommando grep sucht hier in allen Dateien nach dem Wort “bla”. In datei1 und datei2 wird es fündig, bei verz beschwert es sich darüber, dass verz ein Verzeichnis und keine Datei ist. (Neuere grep-Versionen ignorieren Verzeichnisse klaglos, aber das im Test benutzte grep 2.4.2 von Debian Linux akzeptiert keine Verzeichnisse.)
In welche Richtung?
Woher ein Befehl seine Eingaben bezieht und wohin er seine Ausgaben schreibt, ist dem Programm egal. Mit speziellen Operatoren geben Sie den Standardkanälen eine neue Ausrichtung. Wollen Sie zum Beispiel die Standardausgabe nicht auf der Konsole sehen, verwenden Sie den Operator >:
huhn@asteroid:~$ grep bla * > grep_ergebnis grep: verz: Is a directory
Statt des einfachen Operators > könnten Sie hier auch 1> schreiben – die Standardausgabe ist ja mit dem File Descriptor 1 belegt. Wird die 1 weggelassen, ist automatisch stdout gemeint. Während das Ergebnis des grep-Aufrufs in der Datei grep_ergebnis landet, erscheinen Fehlermeldungen weiterhin auf der aktiven Konsole. Wer also lieber die Standardfehlerausgabe umleitet und die Standardausgabe sehen möchte, verwendet statt dessen den Operator 2>:
huhn@asteroid:~$ grep bla * 2> grep_fehler datei1:bla datei2:bla bla
Interessiert die Fehlerausgabe eines Programmes nicht, können Sie diese statt in eine Datei auch nach /dev/null umleiten – diese “Pseudo-Datei” besitzt keinen Inhalt; alle Daten, die Sie auf dieses Gerät schreiben, werden ignoriert. Unerwünschte Fehlermeldungen lassen sich so geschickt aus der Welt schaffen:
grep bla * 2> /dev/null
Der >-Operator leitet nicht nur einfach um – er legt die danach genannte Datei an oder überschreibt sie, falls sie schon existiert. Sie können daher als Alternative das doppelte Größerzeichen >> verwenden: Gibt es die Zieldatei noch nicht, wird sie angelegt; besteht sie hingegen schon, werden die Ausgaben einfach angehängt.
Wer Standardausgabe und Standardfehlerausgabe gemeinsam in eine einzige Datei umleiten möchte, benutzt den Operator >&:
grep bla * >& grep_ergebnis
Einleitung
Neben der Ausgabe können Sie auch die Eingabe umleiten. Dazu verwenden Sie den Operator <. So kann ein Befehl seine Eingabe nicht nur über die Tastatur bekommen, sondern auch aus einer Datei. Gerade im Zusammenhang mit dem Kommando mail[1] ist das oft nützlich: Um einen vorbereiteten Text an den User petronella zu verschicken, reicht ein:
mail -s "brief" petronella < brieftext
Im Aufruf setzt die Option -s den Betreff (engl.: Subject) der Nachricht. mail verschickt dann die mit < eingelesene Datei brieftext.
In die Röhre schauen?
Mit dem Pipe-Zeichen (“|”) verknüpfen Sie Aus- und Eingabestrom und ketten so Befehle aneinander. Um beispielsweise die Ausgabe des Kommandos ls -l /etc/* im Pager less anzuzeigen, tippen Sie:
ls -l /etc/* | less
Ohne diese Umleitung scrollt die Ausgabe des ls-Befehls einfach aus dem Fenster heraus. Es ist auch möglich, mehrere dieser Pipelines hintereinander zu verwenden:
huhn@asteroid:~$ du ~ | sort -rn | less 15237932 /home/huhn 1598024 /home/huhn/digicam 1518428 /home/huhn/uni 1500236 /home/huhn/tmp 1246740 /home/huhn/uni/anglistik […]
Hier schaut zunächst das Kommando du[2] in allen Unterverzeichnissen des Home-Verzeichnis (abgekürzt durch die Tilde ~) nach, welche Dateien wie viel Platz belegen. Um herauszufinden, wer nun genau den meisten Platz belegt, leiten Sie die Ausgabe des du-Kommandos an den Befehl sort[3] weiter. Die beiden Parameter -r und -n sorgen dabei dafür, dass die Ausgabe in umgekehrter Reihenfolge erscheint und numerisch sortiert wird. Die zweite Pipe sorgt dafür, dass die Ausgabe der Befehle seitenweise erscheint.
Tee-Time
Praktisch in Zusammenhang mit komplexen Pipelines ist das Tool tee. Der Name leitet sich aber nicht vom Heißgetränk ab, sondern vom “T-Stück” – etwa als Verbinder und Abzweig zwischen zwei Rohrleitungen. Das Kommando tee erwartet Daten aus der Standardeingabe und reicht sie unverändert an die Standardausgabe durch – kopiert sie aber gleichzeitig in die angegebene Datei. Die allgemeine Syntax von tee lautet:
tee [-option] datei
Das T-Stück können Sie über eine Pipe zwischen zwei Befehlen einfügen. tee nimmt dann die Ausgabe des ersten Befehls entgegen, leitet sie in eine Datei und zusätzlich an das nächste Kommando weiter:
huhn@asteroid:~$ who | tee eingeloggt.txt | grep huhn huhn :0 Apr 29 13:45
Hier schaut der Befehl who zunächst nach, wer auf dem System eingeloggt ist. Die Ausgabe durchsucht der grep-Befehl nach “huhn”. Das in der Mitte eingefügte Kommando tee sorgt dafür, dass die who-Ausgabe vorher in der Datei eingeloggt.txt landet.
Der Befehl tee kennt zwei interessante Optionen: Mit -a (“append”) hängen Sie Daten an eine bereits bestehende Datei an. Ohne diese Option überschreibt tee diese bei jedem neuen Aufruf. Die Option -i verhindert, dass sich tee beim Auftreten von Interrupts ([Strg-c]) im Datenstrom beendet.
tee kommt häufig zum Einsatz, wenn viele durch Pipes verbundene Kommandos im Einsatz sind. Eine Zwischenspeicherung von einzelnen Ausgaben in temporäre Dateien kann beim Aufspüren und Beheben von Fehlern in der Befehlskette helfen. Läuft alles glatt, können die T-Stücke einfach herausgenommen werden. Eine weitere Einsatzmöglichkeit ist das “Protokollieren” eines Kommandos, das sehr viel Zeit in Anspruch nimmt, z. B.:
tar cvf backup.tar * | tee backup.log
Zusätzlich zum Tar-Archiv wird hier ein Logfile angelegt, das Sie auch noch später zu Kontrollzwecken anschauen können. Eine alternative Umleitung des tar-Kommandos mit > backup.log unterdrückt die Ausgabe ins Fenster, die zuvor durch den Parameter v eingeschaltet wurde, und Sie müssten den Fortschritt von tar mit dem Befehl tail -f backup.log in einem anderen Terminal verfolgen.
Glossar
-
File Descriptor
-
Jeder Prozess verwaltet unter Linux eine Liste aller geöffneten Dateien, jeder Eintrag in dieser Liste hat eine eindeutige Nummer, die auch File Descriptor genannt wird. Die Descriptors 0, 1 und 2 werden automatisch erzeugt, da jeder Prozess mit geöffneter Standardein-, -aus- und -fehlerausgabe startet.
Infos
[1] mail: Heike Jurzik, “Minimal mit mail”, LinuxUser 03/2003, S. 82
[2] df und du: Heike Jurzik, “Das richtige Maß”, LinuxUser 01/2004, S. 78
[3] sort: Heike Jurzik, “Richtige Reihenfolge”, LinuxUser 04/2002, S. 76





