Zurück

1.103.4

Benutzen von Unix Streams, Pipes und Umleitungen


Beschreibung: Prüfungskandidaten sollten in der Lage sein, Ein- und Ausgabeströme umzuleiten und sie zu verknüpfen, um Textdaten effizient zu verarbeiten. Dieses Lernziel beinhaltet das Umleiten von Standardeingabe, Standardausgabe und Standardfehlerausgabe, das Umleiten der Ausgabe eines Kommandos in die Eingabe eines anderen Kommandos, das Verwenden der Ausgabe eines Kommandos als Argument für ein anderes Kommando und das gleichzeitige Senden einer Ausgabe sowohl an die Standardausgabe als auch in eine Datei.

Die wichtigsten Dateien, Bezeichnungen und Anwendungen:


Grundlegendes Prinzip

Jedes Programm unter Linux besitzt drei Standardkanäle für die Datenein/ausgabe. Diese drei Kanäle sind

Standard-Eingabe (STDIN)
Der Kanal, von dem das Programm seine Eingabe erwartet. Dieser Kanal besitzt die Kenn-Nummer 0 und ist normalerweise mit der Tastatur verbunden.
Standard-Ausgabe (STDOUT)
Der Kanal, auf den das Programm seine Ausgaben schreibt. Dieser Kanal besitzt die Kenn-Nummer 1 und ist normalerweise mit dem Monitor verbunden.
Standard-Fehlerausgabe (STDERR)
Der Kanal, auf den das Programm seine Fehlerausgaben schreibt. Dieser Kanal besitzt die Kenn-Nummer 2 und ist wie STDOUT normalerweise mit dem Monitor verbunden.

Schematisch könnten wir das etwa folgendermaßen darstellen:

Der Grund für die Auftrennung von Standard Ausgabe und Standard Fehlerausgabe ist einfach der, daß wir diese Kanäle oftmals umleiten. Und eine Umleitung sorgt natürlich auch dafür, daß die Ausgabe jetzt nicht mehr auf dem Schirm erscheint. Käme es jetzt zu einem Fehler, so würden wir es nicht mitbekommen, weil die Ausgabe nicht sichtbar ist. Aus diesem Grund gibt es die separate Fehlerausgabe, die dafür sorgt, daß Fehlerausgaben immer noch auf dem Bildschirm zu lesen sind, auch wenn die Ausgabe umgeleitet wurde.

Umleitungen

Die Shell verwaltet die Ein- und Ausgabekanäle. Sie ist es auch, die diese Kanäle umleiten kann. Das Programm selbst merkt von dieser Umleitung nichts, es schreibt weiterhin auf die Standard Ausgabe und liesst von der Standard Eingabe. Die Shell bietet uns vier Möglichkeiten der Umleitungen. Zwei für die Eingabe und zwei für die Ausgabe:

UmleitungBedeutung
Programm > Datei Das Programm leitet seine Standard Ausgabe in die Datei um, statt sie auf den Bildschirm zu schreiben. Existiert die Datei schon, so wird sie überschrieben, existiert sie noch nicht, so wird sie neu angelegt.
Programm >> Datei Das Programm leitet seine Standard Ausgabe in die Datei um, statt sie auf den Bildschirm zu schreiben. Existiert die Datei schon, so wird die Ausgabe hinten an die bestehende Datei angehängt, existiert sie noch nicht, so wird sie neu angelegt.
Programm < Datei Das Programm ließt seine Eingabe aus der Datei statt von der Tastatur.
Programm << EOM
...
EOM
Das Programm ließt seine Eingaben statt von der Tastatur aus dem Block zwischen den beiden EOM Marken. Dabei dürfen diese Marken beliebige Worte sein, es gilt immer vom ersten bis zum zweiten Auftreten der Marke. Diese Konstruktion wird "here-document" genannt und findet Anwendung fast ausschließlich in der Scriptprogrammierung.

Manchmal ist es auch sinnvoll oder gewünscht, den Fehlerausgabekanal umzuleiten. Das ist über die Nennung seiner Kenn-Nummer vor dem Umleitungssymbol möglich. So würde die Anweisung

  Programm 2> Fehlerprotokoll
die Fehlerausgabe des Programms in die Datei Fehlerprotokoll umleiten. Selbstverständlich ist das auch mit 2 Umleitungssymbolen (anhängend) möglich.

Und in einigen Fällen sollen beide Ausgabekanäle (STDOUT und STDERR) doch in eine Datei umgeleitet werden. Dazu kann man beide Kanäle zu einem zusammenfassen, der dann umgeleitet wird. Das geschieht mit der kryptischen Anweisung 2>&1. Aber vorsicht, um wirklich beide Kanäle in eine Datei umzuleiten muß die Bündelung nach der eigentlichen Umleitung vorgenommen werden:

  Programm > Datei 2>&1
Diese Anweisung bündelt die Kanäle 2 und 1 (STDERR und STDOUT) und leitet beide in die Datei um.

Verkettung (piping)

Wenn wir jetzt zwei Programme haben, von denen das zweite die Ausgabe des ersten weiterverarbeiten sollte, so könnten wir jetzt die Ausgabe des ersten Programms in eine Datei umleiten und dann das zweite Programm aufrufen und seine Eingabe aus der Datei lesen lassen:
  Programm1 > Datei
  Programm2 < Datei
Das können wir auch ohne den Umweg über die Datei haben, indem wir zwei Programme direkt miteinander verbinden. Genauer gesagt verbinden wir die Standard-Ausgabe des ersten Programms mit der Standard-Eingabe des zweiten.

Dazu benutzen wir das Symbol | so daß wir einfach nur schreiben müssen:

  Programm1 | Programm2
Das läßt sich beliebig fortsetzen, es ist also möglich, auch mehrere Programme hintereinanderzuhängen.

xargs

Das Programm xargs bietet eine Möglichkeit, die stark an die Kommandosubstitution erinnert. Hauptsächlich wird dieses Programm in Shells benötigt, die keine Substitution bieten, aber es gibt auch Fälle, in denen mit xargs elegantere Lösungen möglich sind, als mit der Kommandosubstitution.

xargs führt ein beliebiges Kommando aus, und gibt diesem Kommando als Parameter das mit, was xargs von der Standard-Eingabe gelesen hat. In einer Pipe ist es also möglich, daß ein Programm seine Ausgaben an xargs weiterleitet und xargs führt dann ein anderes Programm aus, das mit eben der Ausgabe des ersten Programms als Parameter bestückt wird. Ein simples Beispiel:

Wir haben eine Datei mit Namen Liste, die folgenden Inhalt hat:

  datei1 
  datei2 
  datei3 datei4 
  datei5 /home/hans
Jetzt rufen wir folgenden Befehl auf:
  cat Liste | xargs cp
Der Befehl cat Liste gibt den Inhalt der Datei Liste auf die Standard-Ausgabe aus. Diese ist aber mit der Standard-Eingabe von xargs cp verbunden. xargs ruft also den Befehl cp auf und gibt ihm das mit, was es selbst von der Standard-Eingabe gelesen hat - also in unserem Fall den Inhalt der Liste. Zeilentrenner werden dabei wie Leerzeichen interpretiert. xargs ruft also folgenden Befehl auf:
  cp datei1 datei2 datei3 datei4 datei5 /home/hans
Den selben Effekt hätten wir mit Kommandosubstitution mit folgender Zeile erreichen können:
   cp `cat Liste`
Der Vorteil von xargs liegt darin, daß beliebig lange Ergebnisse mitgegeben werden können, weil xargs die Parameterkette aufteilt und das Programm entsprechend oft hintereinander aufruft. Die Kommandosubstitution kann das nicht und stößt irgendwann an die Grenzen der erlaubten Kommandolänge.

xargs kennt noch viele verschiedenen Kommandozeilenparameter, die aber für die LPI-101 Prüfung eher irrelevant sind.

Zwischensicherung

Die Ausnutzung komplexer Pipekonstruktionen erfordert es oft, daß einzelne Zwischenschritte während des Ablaufs in eine Datei gespeichert werden. Dazu gibt es das Programm tee, das einfach seine Standard-Eingabe auf seine Standard-Ausgabe weitergibt und daneben aber auch den Datenstrom in eine Datei zwischenspeichert. Es handelt sich also um eine Art T-Stück in einer Pipe (Rohrleitung) - daher stammt auch der Name.

Das folgende Konstrukt gibt ein Beispiel für die Anwendung:

  Programm1 | tee Datei1 | Programm2 | tee Datei2 | Programm3 > Datei3 
Das Programm1 schickt seine Ausgabe an das Programm tee, das sie dann in die Datei1 schreibt, aber gleichzeitig auch wieder an das Programm2 weitergibt. Dieses Programm gibt wiederum seine Ausgabe auf eine weitere Instanz von tee weiter, welches sie wieder in die Datei2 schreibt und an das Programm3 weiterleitet. Das dritte Programm schließlich speichert sein Ergebnis in der Datei3. Wir haben also alle Zwischenergebnisse einzeln gespeichert, also das gleiche Ergebnis, als hätten wir geschrieben:
  Programm1 > Datei1
  Programm2 < Datei1 > Datei2
  Programm3 < Datei2 > Datei3