- Standardfehler (
stderr) und Standardausgabe (stdout) werden mit dieser Umleitungssyntax zu einem Stream zusammengeführt
- Die Zahl 1 steht für
stdout, 2 für stderr; & kennzeichnet einen Verweis auf einen Dateideskriptor
2>&1 bedeutet: „Leite stderr an das Ziel um, auf das stdout aktuell zeigt“; je nach Reihenfolge der Umleitungen fällt das Ergebnis unterschiedlich aus
- Zum Beispiel leitet
command >file 2>&1 beide Streams in die Datei um, während bei command 2>&1 >file nur stderr in der Konsole bleibt
- Eine zentrale Umleitungssyntax, die in Bash- und POSIX-Shells häufig für Zusammenführen von Ausgaben, Log-Speicherung und Pipe-Verarbeitung verwendet wird
Dateideskriptoren und Grundbegriffe
- 0, 1, 2 stehen jeweils für
stdin, stdout, stderr
- Definiert in
/usr/include/unistd.h
#define STDIN_FILENO 0, #define STDOUT_FILENO 1, #define STDERR_FILENO 2
> steht für Ausgabenumleitung, `` für das Neuschreiben einer Datei, >> für das Anhängen an eine Datei
- Das Symbol
& zeigt an, dass kein Dateiname, sondern ein Dateideskriptor referenziert wird
- Daher leitet
2>1 in eine Datei mit dem Namen 1 um, während 2>&1 stderr auf stdout dupliziert
Funktionsweise von 2>&1
2> bedeutet, dass stderr umgeleitet werden soll; &1 verweist auf den Dateideskriptor von stdout
- Dadurch zeigt
stderr letztlich auf dasselbe Ziel wie stdout
- Beispiele:
ls -ld /tmp /tnt >/dev/null 2>&1 → beide Ausgaben werden nach /dev/null verworfen
ls -ld /tmp /tnt 2>&1 >/dev/null → nur stderr bleibt in der Konsole
- Umleitungen werden von links nach rechts verarbeitet; daher führt eine andere Reihenfolge zu einem anderen Ergebnis
Warum die Reihenfolge der Umleitung wichtig ist
command >file 2>&1
- Zuerst wird
stdout in die Datei umgeleitet, danach wird stderr auf stdout dupliziert → beide Streams landen in der Datei
command 2>&1 >file
- Zuerst wird
stderr auf das aktuelle stdout (Konsole) dupliziert, danach wird nur stdout in die Datei umgeleitet → stderr erscheint weiterhin in der Konsole
- Da Bash Umleitungen der Reihe nach verarbeitet, ist bei der Formulierung von Befehlen auf die Reihenfolge zu achten
Verschiedene Umleitungsbeispiele
echo test >file.txt → stdout in eine Datei
echo test 2>file.txt → stderr in eine Datei
echo test 1>&2 → stdout nach stderr
command &>file oder command >&file → sowohl stdout als auch stderr in eine Datei (Bash-Kurzform)
command 2>&1 | tee -a file.txt → beide Streams gleichzeitig in Datei und Terminal ausgeben
Erweiterte Nutzung und Funktionen ab Bash 4.0
- Seit Bash 4.0 ist mit Process Substitution auch eine getrennte Ausgabe möglich
ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /')
stdout und stderr werden jeweils an unterschiedliche Filter übergeben
|& ist die Kurzform von 2>&1 | und leitet beide Streams gemeinsam in eine Pipe
- Die Option
set -o noclobber verhindert das Überschreiben bestehender Dateien; mit >| kann eine Ausnahme erzwungen werden
Beispiele aus der Praxis
g++ main.cpp 2>&1 | head → nur die ersten Ausgaben inklusive Compilerfehler anzeigen
perl test.pl > debug.log 2>&1 → sämtliche Ausgaben und Fehler in einer Logdatei speichern
foo 2>&1 | grep ERROR → in stdout und stderr nach der Zeichenfolge ERROR suchen
docker logs container 2>&1 | grep "some log" → die vollständigen Logs per Pipe weiterleiten
Kernaussagen
2>&1 ist die POSIX-Standardsyntax, um stderr auf stdout zu duplizieren
- Da die Reihenfolge der Umleitung das Ergebnis bestimmt, ist beim Schreiben von Befehlen Vorsicht geboten
- In Bash lassen sich mit
&> beide Streams gleichzeitig behandeln;
die Syntax ist unverzichtbar in vielen Automatisierungsskripten für Log-Verwaltung, Pipe-Verarbeitung und Fehlerzusammenführung
1 Kommentare
Hacker-News-Kommentare
Aus Sicht der syscall API von Unix bedeutet
2>&1dasselbe wiedup2(1, 2)In klassischen Unix-Shells ist das alles, aber moderne Shells fügen internes Bookkeeping zur Zustandsverfolgung hinzu
Redirections werden von links nach rechts nacheinander ausgeführt, und der Pipe-Operator arbeitet als Kombination aus fork und dup
Wenn man
dup2(2, 1)allerdings als2<1versteht, wirkt das intuitiv, ist in Bezug auf die I/O-Semantik aber falschZwischen der man7-dup2-Dokumentation und der Arch-Linux-dup2-Dokumentation
Erstaunlich, dass Bots das hier lesen
Zu viel syntaktischer Zucker verdeckt die internen Mechanismen
Anders als bei Sprachen wie Lisp, die einfache Strukturen per Makros erweitern, sind die Syntaxregeln der Shell komplex und wenig intuitiv
Letztlich scheinen solche Beschwerden aus einem Zusammenstoß von Egos zwischen Programmierern und Systemadministratoren zu entstehen
Wenn man sie allerdings nicht vorher öffnet, erhält man den Fehler „Bad file descriptor“
Redirections verwenden vor
execein dup, und Pipes verwenden zwei fork-Aufrufe und denpipe-syscallDas BASH-Handbuch ist wirklich gut, daher lohnt sich ein Blick in die offizielle Dokumentation
In modernen Sprachen oder Sprachen außerhalb von Unix geht dieses Gefühl jedoch verloren
Am Ende ist es am verlässlichsten, die offizielle Dokumentation (RTFM) direkt zu lesen
Bash-Redirections-Handbuch
Die meisten googeln nach Antworten, und erst wenn sich solche Fragen ansammeln, entstehen entsprechende Suchergebnisse
Die verschiedenen Perspektiven auf Stack Overflow sind für Einsteiger oft hilfreicher
Für normale Nutzer ist es schwer, die gewünschten Informationen zu finden
Eine Antwort auf Stack Overflow drückt genau das aus, was ich denke, deshalb zitiere ich sie wörtlich
Der Grund, warum es
2>&1und nicht&2>&1heißt, ist, dass&nur im Kontext von Redirection einen File Descriptor bedeutetInteressant ist, dass PowerShell dieselbe Syntax beibehalten hat
Link zur offiziellen Dokumentation
Die Reihenfolge von
2>&1 > fileist im Vergleich zu Unix umgekehrt, sodass nicht das beabsichtigte Ergebnis herauskommtVor Version 7.4 gab es außerdem Probleme mit beschädigten Bytestreams
Zugehörige Dokumentation
>gibt an, welcher File Descriptor umgeleitet werden soll>fooist dasselbe wie1>fooWenn man
2>>&1schreibt, entsteht eine Datei namens1, daher ist das bedeutungslos>bedeutet stdout,2>bedeutet stderr und&1bedeutet stdoutfile1>file2ist ebenfalls nicht symmetrisch/dev/stderr>/dev/stdoutist die direktere EntsprechungClaudes Erklärung war am leichtesten zu verstehen
2>&1bedeutet: „Leite die Fehlerausgabe an denselben Ort wie die normale Ausgabe weiter“2steht für Fehlerausgabe,>für „senden“ und&1für „den Ort, auf den stdout aktuell zeigt“2für File Descriptor 2,>für Zuweisung und&1für File Descriptor 1Den Link direkt anzuklicken ist effizienter, als es von einem LLM erklären zu lassen
Ich vermisse die Stack-Overflow-Zeit, in der man noch Menschen Fragen stellte
Aber inzwischen ist es schwer, zu dieser Zeit zurückzukehren
Allerdings gab es damals auch viel Gatekeeping und eine zynische Atmosphäre
Menschzentrierte Zusammenarbeit ist nicht immer romantisch
Ohne unnötige Einleitung direkt auf den Punkt
Im Umgang mit Menschen gibt es soziale Lasten wie Taktgefühl, Bewertung und Konkurrenzdenken
LLMs geben ohne solche Belastungen neutrale und höfliche Antworten
Das Verhalten der Shell ist kontextabhängig, daher ändert sich die Bedeutung von
&je nach PositionWie bei
IFS=\| read A B C <<< "first|second|third"gilt es nur lokal innerhalb einer ZeileEin
&am Zeilenende bedeutet Ausführung im Hintergrund, ein&in der Mitte bedeutet RedirectionSolche Muster sind schwer zu lernen, aber man muss sie letztlich beherrschen
Es wird einem wieder bewusst, wie uralt die Systeme sind, die wir benutzen
File Descriptors als Zahlen zu behandeln ist so, als würde man dem Nutzer direkt Pointer geben
Ein namensbasierter Zugriff wäre wünschenswert
&signalisiert nur, dass es keine Datei, sondern ein Descriptor ist<ist bereits für Input-Redirection belegt und konnte daher nicht als Ersatz dienen2>/dev/stdoutist2>&1ähnlich, aber nicht völlig identisch/dev/stdoutist ein vertrauterer namensbasierter ZugriffEin Skript von vor 15 Jahren läuft heute noch unverändert
Redirection ist wirklich eine faszinierende Funktion
Ich verwende zum Beispiel oft Prozesssubstitution wie in
diff <(seq 1 20) <(seq 1 10)Wenn man Dateien, Streams und Sockets direkt an Prozesse übergeben könnte, wäre das viel mächtiger
Wenn Bash Sockets direkt öffnen und an andere Programme weitergeben könnte, wäre auch Sandboxing einfacher
[^1]:
/dev/tcpgibt es, aber die Funktionalität ist eingeschränktTatsächlich ist das als named pipe implementiert, daher ist seek nicht möglich
Deshalb hat Zsh die Syntax
=(command)ergänzt, die temporäre Dateien verwendetIch habe mir
2>&1so gemerkt und verstanden: „2 geht an die Adresse von 1“Ein Artikel, der sich ausführlich mit
2>&1und Redirection beschäftigt:Understanding Linux's File Descriptors: A Deep Dive Into '2>&1' and Redirection
Link zur zugehörigen Diskussion
Link zum Buch