[[Vorlage(Getestet, general)]] [[Inhaltsverzeichnis(1)]] [[Bild(Wiki/Icons/terminal.png, 48, align=left)]] Beim Arbeiten im Terminal bietet die [:Bash:] verschiedene Möglichkeiten, die Ausgabe der einzelnen Befehle umzuleiten bzw. an andere Befehle weiterzuleiten. Ebenso besteht die Möglichkeit, dass Befehle, die standardmäßig von der Standardeingabe lesen, alternativ die Eingabe(n) aus einer Datei lesen. Dieser Wiki-Beitrag bezieht sich primär auf die [:Bash:]. Die Umleitungen > , >>, < , << und | stehen in anderen [http://pubs.opengroup.org/onlinepubs/9699919799/ POSIX]-kompatiblen [:Shell:Shells] jedoch in gleicher Form zur Verfügung. Alle Umleitungen gelten für den Prozess, für den sie eingerichtet werden, sowie für dessen Kind-Prozesse. Die Umleitungen können dort allerdings wieder überschrieben werden. Diese Eigenschaft sorgt dafür, dass bei Umleitung der Ausgabe eines Shell-Skriptes sämtliche Ausgaben in dem Skript in denselben Kanal (z.B. Datei) geschrieben werden. [[Anker(Standardausgabe)]] = stdin, stdout, stderr - Kanäle der Bash = Vorab noch ein wenig Hintergrundwissen: Alle Befehle und Programme, welche in der Bash gestartet werden, erhalten drei Kanäle zugewiesen: * Den Standardeingabekanal ''stdin'', dieser hat die Nummer 0 (null). Normalerweise liest stdin Eingaben von der Tastatur, welche mit dem Terminal verbunden ist. * Den Standardausgabekanal ''stdout'', dieser hat die Nummer 1 (eins). Normalerweise schreibt stdout Ausgaben auf den Bildschirm, welcher mit dem Terminal verbunden ist. * Den Standardfehlerkanal ''stderr'', dieser hat die Nummer 2 (zwei). Normalerweise schreibt stderr Ausgaben auf den Bildschirm, welcher mit dem Terminal verbunden ist. = Umleiten der Ausgabe mit > = Mit Hilfe des "Größer als" Zeichens '''>''' lässt sich die Standardausgabe stdout umleiten. Eine typische (und sehr häufige) Anwendung ist das Umleiten in eine Datei. So schreibt zum Beispiel der Befehl {{{#!vorlage Befehl ls > verzeichnis.txt }}} den Inhalt des aktuellen Verzeichnisses in die Datei '''verzeichnis.txt''' anstatt in das Terminal. {{{#!vorlage Warnung Existiert die Datei '''verzeichnis.txt''' nicht, so wird diese angelegt. Existiert die Datei bereits, so wird diese ohne Rückfrage überschrieben, falls die Shell-Option "-C" ("noclobber") nicht gesetzt ist (was der Standardfall ist)! }}} {{{#!vorlage Experten Aus demselben Grund funktioniert beispielsweise auch `sed s/muster/ersetzungstext/ < datei.txt > datei.txt` nicht. Da die Öffnung des umgeleiteten Ausgabekanals - die damit einhergehende Löschung des Inhalts von '''datei.txt''' - der Öffnung des Eingabekanals vorausgeht, arbeitet `sed` mit einer leeren Datei. }}} Es ist aber auch möglich, die Ausgabe an existierende Dateien anzuhängen, in dem man statt ein '''>''' zwei '''>>''' verwendet. Der Befehl {{{#!vorlage Befehl ls ~/Desktop >> verzeichnis.txt }}} hängt den Inhalt von '''~/Desktop''' also an die Datei '''verzeichnis.txt''' an. Neben stdout schreibt auch der Standardfehlerkanal stderr regelmäßig auf das Terminal. Möchte man die Ausgabe von stderr umleiten, muss man `2>` statt `>` verwenden: {{{#!vorlage Befehl ls -la /home/user 2> fehler.txt }}} `2>` heißt soviel wie „leite den Kanal 2 (stderr) um“. {{{#!vorlage Hinweis Der Kanal 1 (stdout) muss bei der Umleitung nicht explizit benannt werden. ">" wird von der Bash automatisch mit "1>" gleichgesetzt. }}} Es lassen sich auch beide Kanäle gleichzeitig in zwei verschiedene Dateien umleiten: {{{#!vorlage Befehl ls -la > verzeichnis.txt 2> fehler.txt }}} So wird die Ausgabe von '''ls''' in die Datei '''verzeichnis.txt''' umgeleitet, Fehlermeldungen in die Datei '''fehler.txt'''. Weiterhin ist es auch möglich, beide Kanäle in eine Datei zu leiten: {{{#!vorlage Befehl ls -la > gemeinsam.txt 2>&1 }}} `2>&1` bedeutet also soviel wie „schreibe die Ausgabe von Kanal 2 (stderr) dorthin, wo die Ausgabe von Kanal 1 (stdout) geschrieben wird“. {{{#!vorlage Hinweis Die Reihenfolge ist wichtig: Es wird immer dorthin umgeleitet, wohin der angegebene Kanal gerade geleitet wird. Stellt man das `2>&1` also vor das `> gemeinsam.txt`, wird stderr auf die Standardausgabe geleitet, nur was ursprünglich auf die Standardausgabe geschrieben wurde, landet in der Datei. }}} Natürlich kann man auch bei Kanal 2 zwei größer-als-Zeichen verwenden. So lassen sich z.B. Fehlermeldungen während einer Datensicherung von Tar an eine Logdatei anhängen: {{{#!vorlage Befehl echo "Sicherung" >> backup.log tar -cf sicherung.tgz "/home" 2>> backup.log }}} Die Verwendung von &> leitet sowohl stdout als auch stderr in die angegebene Datei um. Das ist hilfreich u.a. in Bash-Skripten, in denen lediglich der Rückgabewert von Befehlen interessiert, nicht aber der Ausgabetext. Diese Funktionalität ist nicht verfügbar in der `sh`. Dieses Beispiel beendet ein Skript, wenn irgendeine Datei im [:Homeverzeichnis:] geöffnet ist und unterdrückt dabei jegliche Ausgaben: {{{#!code bash if lsof ~ &>/dev/null; then exit 1; fi }}} In Bash-Versionen 3.x und älter funktioniert die Umleitung mit `&>>` nicht, wobei alle aktuell unterstützen Ubuntu-Versionen alle Bash 4.x mitbringen. Abhilfe schafft das Anhängen von stdout an eine Datei anhängen und die Umleitung von stderr nach stdout. Dieses Beispiel führt ein Kommando aus und hängt sowohl stdout als auch stderr an ein logfile: {{{#!vorlage Befehl ./my_command.sh >> results.log 2>&1 }}} Für interaktive Shells empfiehlt es sich, die Shell-Option -C ("noclobber") zu setzen (z.B. in der ~/.bashrc), die das versehentliche Überschreiben von Dateien verhindert: {{{#!vorlage Befehl $ cat datei welt $ set -C $ echo star > datei bash: datei: cannot overwrite existing file $ cat datei welt }}} Muss man dann doch einmal eine Datei überschreiben, hilft >|: {{{#!vorlage Befehl $ echo star >| datei $ cat datei star }}} Für einen Shell-Prozess und alle Kindprozesse lässt sich die Ausgabe auch global umleiten. Mit {{{#!vorlage Befehl exec > datei.txt }}} sowie sämtlicher in diesem Abschnitt genannten Varianten wird die Ausgabe aller nachfolgenden Befehle in die Datei geschrieben. Eine explizite Umleitung ist dann in den Befehlen nicht mehr erforderlich. Dies kann auch dazu genutzt werden, selektiv in eine Datei auszugeben, die nicht immer wieder geöffnet werden muss: {{{#!vorlage Befehl exec 9> arbeit.log echo 'Wir zeigen das aktuelle Verzeichnis auf der Konsole an.' >&9 ls echo 'Wir sind fertig mit dem Zeigen das aktuellen Verzeichnisses.' >&9 }}} Dieses Vorgehen spart Zeit für das Öffnen der Datei, hat aber vor allem den Vorteil, dass alle Ausgaben garantiert in der selben Datei landen. (Andernfalls wenn beim Arbeiten mit >> die Datei umbenannt wird, gelangen die Ausgaben in verschiedene Dateien.) {{{#!vorlage Experten Normalerweise müssen Kanäle nicht geschlossen werden, da der Kernel das beim Beenden eines Prozesses automatisch tut. Sollte es in seltenen Fällen doch nötig sein, kann man das durch die Umleitung von oder auf &- erreichen. Damit wird der umgeleitete Kanal geschlossen. Im obigen Beispiel mit `exec` würde Kanal 9 mit `exec 9>&-` geschlossen werden. }}} = Umleitung der Eingabe mit < = Mit Hilfe des „Kleiner als“-Zeichens '''<''' lässt sich die Standardeingabe (stdin) umleiten. Beispiel: {{{#!vorlage Befehl tr -d '0-9' < datei.txt }}} Dieser Aufruf zeigt den Inhalt aus '''datei.txt''' ohne Ziffern an. Bei Verdoppelung des Zeichens '''<<''' kann man auf der Standardeingabe auch eine Pseudodatei erzeugen (sogenanntes Hier-Dokument), die dann sequenziell gelesen wird. Hinter dem Zeichen ist ein Schlüsselwort einzugeben, welches das „Dateiende“ symbolisiert. Beispiel: {{{#!vorlage Befehl while read d do touch $d done << eod aufdieplaetze.txt fertig.txt los.txt eod }}} In dem Beispiel werden in einem Durchgang drei Dateien mit den im Hier-Dokument enthaltenen Namen erzeugt. = Der Pipe-Operator | = Der Pipe-Operator (Pipe = Kurzform für Pipeline) leitet die Ausgabe eines Befehls direkt an einen anderen Befehl weiter (anstatt ins Terminal). Damit kann der zweite Befehl das Ergebnis bzw. die Ausgabe des ersten Befehls weiterverarbeiten. Die allgemeine Syntax lautet (man kann natürlich auch mehr als zwei Befehle miteinander verbinden): {{{#!vorlage Befehl Befehl1 | Befehl2 }}} {{{#!vorlage Hinweis Das Zeichen für den Pipe-Operator `|` erhält man auf einer deutschen Tastatur durch Drücken von [[Vorlage(Tasten, altgr+<)]]. }}} Eine typische Anwendung für den Pipe-Operator ist z.B. das Aufrufen eines Befehls, der eine größere Menge an Daten auf stdout schreibt (z.B. Ausgaben von Systemmeldungen wie `dmesg` oder Ausgaben von Prozessinformationen wie [:Shell/ps:ps] und [:Shell/pstree:pstree]) in Kombination mit Datensortierung (z.B. `sort`) oder Durchsuchen der Ausgabe nach bestimmten Ausdrücken (z.B. [:Shell/grep:grep]). Einige Beispiele: * Im ersten Beispiel werden alle laufenden Prozesse durch `ps` ausgegeben, der Pipe-Operator leitet die Ausgabe an `sort` weiter. `sort` sortiert die Daten um (absteigende numerische Sortierung, Option `-nr`) und gibt die umsortierten Daten dann an stdout weiter. {{{#!vorlage Befehl ps ax | sort -nr }}} * Im zweiten Beispiel gibt `dmesg` alle Log-Meldungen des Kernels aus, der Pipe-Operator leitet diese an `grep` weiter. `grep` sucht nur nach Zeilen, in denen der Ausdruck `usb` vorkommt. Die Ausgabe von `grep` erfolgt dann (standardmäßig) auf stdout (der Parameter `-n` sorgt dafür, dass grep die Zeilen nummeriert). {{{#!vorlage Befehl dmesg | grep -n USB }}} * Im dritten Beispiel kommen mehrere Pipelines zum Einsatz. Das zweite Beispiel wird durch einen weiteren Pipe-Operator und den Befehl `tail` ergänzt. Somit werden nur noch die letzten zehn Zeilen angezeigt. {{{#!vorlage Befehl dmesg | grep -n USB | tail }}} * Natürlich lässt sich der Pipe-Operator auch mit der Umleitung von stdin und stdout kombinieren, zum Beispiel: {{{#!vorlage Befehl grep usb < alle-meldungen.log | tail > usb-meldungen.log }}} {{{#!vorlage Hinweis Die Umleitungen müssen übrigens nicht hinter dem Befehl stehen, sie können auch davor oder mittendrin geschrieben werden: {{{#!vorlage Befehl grep < alle-meldungen.log usb | >usb-meldungen.log tail \}}} }}} [[Anker(tee)]] = tee - Ausgabe verdoppeln = Das Programm '''tee''' liest von der Standardeingabe stdin und verdoppelt die eingelesenen Daten. Die Daten werden dann je einmal an eine Datei und an die Standardausgabe stdout weitergeleitet. Weitere Informationen sind im Wikiartikel [:Shell/tee:] zu finden. = Links = * [:script:] - Terminalsitzung mitschneiden * [:Shell/Befehlsübersicht:] {Übersicht} Übersicht über verschiedene Shell-Befehle * [http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_07 Festlegung zu Umleitungen] im [http://pubs.opengroup.org/onlinepubs/9699919799/ POSIX Standard] #tag: Shell