Wenn ich in einer Unix-Shell stderr
und stdout
zur weiteren Bearbeitung im Stream stdout
kombinieren möchte, kann ich am Ende meines Befehls Folgendes anhängen:
2>&1
Wenn ich also head
für die Ausgabe von g++
verwenden möchte, kann ich Folgendes tun:
g++ lots_of_errors 2>&1 | head
so kann ich nur die ersten fehler sehen.
Mir fällt es immer schwer, mich daran zu erinnern, und ich muss ständig nachschlagen, und das liegt hauptsächlich daran, dass ich die Syntax dieses bestimmten Tricks nicht vollständig verstehe.
Kann jemand das aufbrechen und Zeichen für Zeichen erklären, was 2>&1
bedeutet?
Dateideskriptor 1 ist die Standardausgabe (stdout
).
Dateideskriptor 2 ist der Standardfehler (stderr
).
Hier ist eine Möglichkeit, sich an dieses Konstrukt zu erinnern (obwohl es nicht ganz genau ist): Auf den ersten Blick kann 2>1
eine gute Möglichkeit sein, stderr
zu stdout
umzuleiten. Tatsächlich wird es jedoch als "stderr
in eine Datei mit dem Namen 1
umleiten" interpretiert. &
gibt an, dass das Folgende ein Dateideskriptor und kein Dateiname ist. So wird das Konstrukt: 2>&1
.
echo test > afile.txt
leitet stdout zu afile.txt
um. Dies ist das gleiche wie das, was Sie tun
echo test 1> afile.txt
Um stderr umzuleiten, tun Sie Folgendes:
echo test 2> afile.txt
>&
ist die Syntax zum Umleiten eines Streams zu einem anderen Dateideskriptor - 0 ist stdin, 1 ist stdout und 2 ist stderr.
Sie können stdout nach stderr umleiten, indem Sie Folgendes tun:
echo test 1>&2 # or echo test >&2
Oder umgekehrt:
echo test 2>&1
Kurz gesagt, 2>
leitet stderr in eine (nicht spezifizierte) Datei um, indem &1
stderr an stdout angehängt wird.
Einige Syntax-Besonderheiten können wichtige Verhaltensweisen haben. Es gibt einige kleine Beispiele für Weiterleitungen, STDERR
, STDOUT
und Argumente , die die Reihenfolge festlegen.
Symbol _>
_ bedeutet Umleitung .
>
_ bedeutet Senden an eine vollständige Datei , Überschreiben des Ziels, falls vorhanden (siehe noclobber
Bash-Funktion bei # 3 später).>>
_ Mittelwert , der zusätzlich zu gesendet wird, würde an das Ziel angehängt, falls vorhanden.In jedem Fall wird die Datei erstellt, wenn sie nicht vorhanden ist.
Um dies zu testen, benötigen wir einen einfachen Befehl, der an beiden Ausgängen etwas sendet :
_$ ls -ld /tmp /tnt
ls: cannot access /tnt: No such file or directory
drwxrwxrwt 118 root root 196608 Jan 7 11:49 /tmp
$ ls -ld /tmp /tnt >/dev/null
ls: cannot access /tnt: No such file or directory
$ ls -ld /tmp /tnt 2>/dev/null
drwxrwxrwt 118 root root 196608 Jan 7 11:49 /tmp
_
(Vorausgesetzt, Sie haben kein Verzeichnis mit dem Namen _/tnt
_;). Nun, wir haben es !!
Also mal sehen:
_$ ls -ld /tmp /tnt >/dev/null
ls: cannot access /tnt: No such file or directory
$ ls -ld /tmp /tnt >/dev/null 2>&1
$ ls -ld /tmp /tnt 2>&1 >/dev/null
ls: cannot access /tnt: No such file or directory
_
Die letzte Befehlszeile gibt STDERR
an die Konsole aus, und es scheint nicht das erwartete Verhalten zu sein ... Aber ...
Wenn Sie eine Nachfilterung für eine Ausgabe durchführen möchten, für die andere oder für beide:
_$ ls -ld /tmp /tnt | sed 's/^.*$/<-- & --->/'
ls: cannot access /tnt: No such file or directory
<-- drwxrwxrwt 118 root root 196608 Jan 7 12:02 /tmp --->
$ ls -ld /tmp /tnt 2>&1 | sed 's/^.*$/<-- & --->/'
<-- ls: cannot access /tnt: No such file or directory --->
<-- drwxrwxrwt 118 root root 196608 Jan 7 12:02 /tmp --->
$ ls -ld /tmp /tnt >/dev/null | sed 's/^.*$/<-- & --->/'
ls: cannot access /tnt: No such file or directory
$ ls -ld /tmp /tnt >/dev/null 2>&1 | sed 's/^.*$/<-- & --->/'
$ ls -ld /tmp /tnt 2>&1 >/dev/null | sed 's/^.*$/<-- & --->/'
<-- ls: cannot access /tnt: No such file or directory --->
_
Beachten Sie, dass die letzte Befehlszeile in diesem Absatz genau die gleiche ist wie in dem vorherigen Absatz, in dem ich geschrieben habe , scheint nicht das erwartete Verhalten zu sein (dies könnte also sogar ein erwartetes Verhalten sein). .
Nun, es gibt ein paar Tricks zu Umleitungen, um an beiden Ausgängen unterschiedliche Operationen auszuführen :
_$ ( ls -ld /tmp /tnt | sed 's/^/O: /' >&9 ) 9>&2 2>&1 | sed 's/^/E: /'
O: drwxrwxrwt 118 root root 196608 Jan 7 12:13 /tmp
E: ls: cannot access /tnt: No such file or directory
_
Hinweis: _&9
_ Deskriptor würde spontan aufgrund von _) 9>&2
_ auftreten.
Nachtrag: nota! Mit der neuen Version von bash (_>4.0
_) gibt es eine neue Funktion und mehr sexy Syntax für diese Art von Dingen:
_$ ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /')
O: drwxrwxrwt 17 root root 28672 Nov 5 23:00 /tmp
E: ls: cannot access /tnt: No such file or directory
_
Und zum Schluss für eine solche kaskadierende Ausgabeformatierung:
_$ ((ls -ld /tmp /tnt |sed 's/^/O: /' >&9 ) 2>&1 |sed 's/^/E: /') 9>&1| cat -n
1 O: drwxrwxrwt 118 root root 196608 Jan 7 12:29 /tmp
2 E: ls: cannot access /tnt: No such file or directory
_
Nachtrag: nota! Gleiche neue Syntax in beiden Richtungen:
_$ cat -n <(ls -ld /tmp /tnt 2> >(sed 's/^/E: /') > >(sed 's/^/O: /'))
1 O: drwxrwxrwt 17 root root 28672 Nov 5 23:00 /tmp
2 E: ls: cannot access /tnt: No such file or directory
_
Wenn STDOUT
einen bestimmten Filter durchläuft, STDERR
einen anderen und schließlich werden beide zusammengeführten Ausgänge durch einen dritten Befehlsfilter geleitet.
noclobber
-Option und zur _>|
_ -SyntaxDas ist ungefähr Überschreiben :
Während _set -o noclobber
_ die Bash anweist, keine vorhandenen Dateien zu überschreiben , können Sie mit der _>|
_ -Syntax diese Einschränkung umgehen:
_$ testfile=$(mktemp /tmp/testNoClobberDate-XXXXXX)
$ date > $testfile ; cat $testfile
Mon Jan 7 13:18:15 CET 2013
$ date > $testfile ; cat $testfile
Mon Jan 7 13:18:19 CET 2013
$ date > $testfile ; cat $testfile
Mon Jan 7 13:18:21 CET 2013
_
Die Datei wird nun jedes Mal überschrieben:
_$ set -o noclobber
$ date > $testfile ; cat $testfile
bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
Mon Jan 7 13:18:21 CET 2013
$ date > $testfile ; cat $testfile
bash: /tmp/testNoClobberDate-WW1xi9: cannot overwrite existing file
Mon Jan 7 13:18:21 CET 2013
_
Weiter mit _>|
_:
_$ date >| $testfile ; cat $testfile
Mon Jan 7 13:18:58 CET 2013
$ date >| $testfile ; cat $testfile
Mon Jan 7 13:19:01 CET 2013
_
Deaktivieren Sie diese Option und/oder fragen Sie nach, falls bereits festgelegt.
_$ set -o | grep noclobber
noclobber on
$ set +o noclobber
$ set -o | grep noclobber
noclobber off
$ date > $testfile ; cat $testfile
Mon Jan 7 13:24:27 CET 2013
$ rm $testfile
_
Für die Umleitung beider Ausgaben eines gegebenen Befehls sehen wir, dass eine richtige Syntax sein könnte:
_$ ls -ld /tmp /tnt >/dev/null 2>&1
_
für diesen Sonderfall gibt es eine Abkürzungssyntax: _&>
_ ... oder _>&
_
_$ ls -ld /tmp /tnt &>/dev/null
$ ls -ld /tmp /tnt >&/dev/null
_
Anmerkung: Wenn 2>&1
existiert, 1>&2
ist auch eine korrekte Syntax:
_$ ls -ld /tmp /tnt 2>/dev/null 1>&2
_
_$ ls -ld /tmp /tnt 2>&1 1>&2 | sed -e s/^/++/
++/bin/ls: cannot access /tnt: No such file or directory
++drwxrwxrwt 193 root root 196608 Feb 9 11:08 /tmp/
$ ls -ld /tmp /tnt 1>&2 2>&1 | sed -e s/^/++/
/bin/ls: cannot access /tnt: No such file or directory
drwxrwxrwt 193 root root 196608 Feb 9 11:08 /tmp/
_
Sie können das Handbuch lesen, indem Sie auf Folgendes klicken:
_man -Len -Pless\ +/^REDIRECTION bash
_
in einer bash Konsole ;-)
Ich habe diesen brillanten Beitrag bei der Weiterleitung gefunden: Alles über Weiterleitungen
Standardausgabe und Standardfehler in eine Datei umleiten
$ befehl &> datei
Dieser Einzeiler verwendet den Operator &>
, um beide Ausgabestreams - stdout und stderr - vom Befehl in die Datei umzuleiten. Dies ist die Abkürzung von Bash, mit der Sie beide Streams schnell an dasselbe Ziel umleiten können.
So sieht die Dateideskriptortabelle aus, nachdem Bash beide Streams umgeleitet hat:
Wie Sie sehen, zeigen nun sowohl stdout als auch stderr auf file
. Also wird alles, was an stdout und stderr geschrieben wurde, an file
geschrieben.
Es gibt verschiedene Möglichkeiten, beide Streams an dasselbe Ziel umzuleiten. Sie können jeden Stream nacheinander umleiten:
$ command> file 2> & 1
Dies ist eine häufigere Methode, um beide Streams in eine Datei umzuleiten. Zuerst wird stdout in die Datei umgeleitet und dann wird stderr so dupliziert, dass es mit stdout identisch ist. Beide Streams zeigen also auf file
.
Wenn Bash mehrere Weiterleitungen sieht, werden diese von links nach rechts verarbeitet. Lassen Sie uns die Schritte durchgehen und sehen, wie das passiert. Vor dem Ausführen von Befehlen sieht die Dateideskriptortabelle von Bash folgendermaßen aus:
Jetzt verarbeitet Bash die erste Umleitungsdatei. Wir haben das schon einmal gesehen und es bringt stdout dazu, zu filen:
Next Bash sieht die zweite Umleitung 2> & 1. Wir haben diese Umleitung noch nie gesehen. Dieser dupliziert den Dateideskriptor 2, um eine Kopie des Dateideskriptors 1 zu sein, und wir erhalten:
Beide Streams wurden in die Datei umgeleitet.
Seien Sie hier jedoch vorsichtig! Schreiben
befehl> Datei 2> & 1
ist nicht dasselbe wie schreiben:
$ befehl 2> & 1> datei
Die Reihenfolge der Weiterleitungen ist in Bash! Dieser Befehl leitet nur die Standardausgabe in die Datei um. Das stderr wird weiterhin auf dem Terminal gedruckt. Um zu verstehen, warum das passiert, gehen wir die Schritte noch einmal durch. Vor dem Ausführen des Befehls sieht die Dateideskriptortabelle folgendermaßen aus:
Jetzt verarbeitet Bash die Weiterleitungen von links nach rechts. Es sieht zuerst 2> & 1, also dupliziert es stderr zu stdout. Die Dateideskriptortabelle wird zu:
Jetzt sieht Bash die zweite Umleitung, >file
, und leitet stdout zur Datei um:
Sehen Sie, was hier passiert? Stdout zeigt jetzt auf file, aber der stderr zeigt immer noch auf das Terminal! Alles, was an stderr geschrieben wird, wird trotzdem auf dem Bildschirm ausgedruckt! Gehen Sie also sehr, sehr vorsichtig mit der Reihenfolge der Weiterleitungen um!
Beachten Sie auch, dass in Bash, schriftlich
$ befehl &> datei
ist genau das gleiche wie:
$ command> & file
Die Zahlen beziehen sich auf die Dateideskriptoren (fd).
stdin
stdout
stderr
2>&1
leitet fd 2 zu 1 weiter.
Dies funktioniert für eine beliebige Anzahl von Dateideskriptoren, wenn das Programm diese verwendet.
Sie können /usr/include/unistd.h
anschauen, wenn Sie sie vergessen haben:
/* Standard file descriptors. */
#define STDIN_FILENO 0 /* Standard input. */
#define STDOUT_FILENO 1 /* Standard output. */
#define STDERR_FILENO 2 /* Standard error output. */
Das heißt, ich habe C-Tools geschrieben, die nicht-standardmäßige Dateideskriptoren für die benutzerdefinierte Protokollierung verwenden, sodass Sie diese nur sehen, wenn Sie sie in eine Datei oder etwas anderes umleiten.
Dieses Konstrukt sendet den Standardfehlerstrom (stderr
) an die Position current der Standardausgabe (stdout
) - dieses Währungsproblem scheint von den anderen Antworten vernachlässigt worden zu sein.
Sie können jedes Ausgabe-Handle mit dieser Methode auf ein anderes umleiten, sie wird jedoch am häufigsten verwendet, um stdout
- und stderr
-Streams zur Verarbeitung in einen einzelnen Stream zu leiten.
Einige Beispiele sind:
# Look for ERROR string in both stdout and stderr.
foo 2>&1 | grep ERROR
# Run the less pager without stderr screwing up the output.
foo 2>&1 | less
# Send stdout/err to file (with append) and terminal.
foo 2>&1 |tee /dev/tty >>outfile
# Send stderr to normal location and stdout to file.
foo >outfile1 2>&1 >outfile2
Beachten Sie, dass das letzte Argument nichtstderr
zu outfile2
leitet - es leitet es zu dem um, was stdout
war, als das Argument angetroffen wurde (outfile1
) und dann leitet stdout
zu outfile2
weiter.
Dies erlaubt einige ziemlich ausgefeilte Tricks.
2>&1
ist ein POSIX-Shell-Konstrukt. Hier ist eine Aufschlüsselung, Token für Token:
2
: " Standardfehler " Ausgabedateideskriptor.
>&
: Duplizieren eines Ausgabedateideskriptors (eine Variante von Ausgabeumleitung Operator >
). Wenn [x]>&[y]
gegeben ist, wird der mit x
bezeichnete Dateideskriptor als Kopie des Ausgabedateideskriptors y
erstellt.
1
" Standardausgabe " Ausgabedateideskriptor.
Der Ausdruck 2>&1
kopiert den Dateideskriptor 1
an den Speicherort 2
, sodass alle Ausgaben, die in der Ausführungsumgebung in 2
("Standardfehler") geschrieben wurden, in dieselbe ursprünglich beschriebene Datei verschoben werden durch 1
("Standardausgabe").
Weitere Erklärung:
Dateideskriptor : "Eine pro Prozess eindeutige, nicht negative Ganzzahl, die zum Identifizieren einer geöffneten Datei zum Zweck der Datei verwendet wird Zugriff."
Standardausgabe/-fehler : Beachten Sie den folgenden Hinweis im Abschnitt Redirection der Shell-Dokumentation:
Geöffnete Dateien werden durch Dezimalzahlen dargestellt, die mit Null beginnen. Der größtmögliche Wert ist implementierungsdefiniert. Alle Implementierungen müssen jedoch mindestens 0 bis einschließlich 9 für die Verwendung durch die Anwendung unterstützen. Diese Nummern werden "Dateideskriptoren" genannt. Die Werte 0, 1 und 2 haben eine spezielle Bedeutung und herkömmliche Verwendungen und werden durch bestimmte Umleitungsoperationen impliziert. Sie werden als Standardeingabe, Standardausgabe bzw. Standardfehler bezeichnet. Programme beziehen ihre Eingabe normalerweise von der Standardeingabe und schreiben die Ausgabe auf die Standardausgabe. Fehlermeldungen werden normalerweise auf Standardfehler geschrieben. Den Umleitungsoperatoren können eine oder mehrere Ziffern vorangestellt werden (wobei keine dazwischen liegenden Zeichen zulässig sind), um die Dateideskriptornummer anzugeben.
2 ist der Konsolenstandardfehler.
1 ist die Standardausgabe der Konsole.
Dies ist das Standard-Unix, und Windows folgt auch dem POSIX.
Z.B. wenn du rennst
Perl test.pl 2>&1
der Standardfehler wird zur Standardausgabe umgeleitet, sodass Sie beide Ausgaben zusammen sehen können:
Perl test.pl > debug.log 2>&1
Nach der Ausführung können Sie alle Ausgaben, einschließlich Fehler, in der debug.log sehen.
Perl test.pl 1>out.log 2>err.log
Dann geht die Standardausgabe nach out.log und der Standardfehler nach err.log.
Ich schlage vor, dass Sie versuchen, diese zu verstehen.
So beantworten Sie Ihre Frage: Es wird jede Fehlerausgabe (normalerweise an stderr gesendet) und in die Standardausgabe (stdout) geschrieben.
Dies ist hilfreich, wenn Sie beispielsweise "mehr" für die gesamte Ausgabe auslagern möchten. Einige Programme drucken beispielsweise Nutzungsinformationen in stderr.
Um Ihnen zu helfen, sich zu erinnern
"2> & 1" zeigt einfach alles, was an stderr gesendet wurde, auf stdout.
Ich empfehle auch das Lesen von dieser Beitrag über die Fehlerumleitung , wo dieses Thema ausführlich behandelt wird.
Aus Sicht eines Programmierers bedeutet dies genau Folgendes:
dup2(1, 2);
Siehe Manpage .
Zu verstehen, dass 2>&1
eine Kopie ist, erklärt auch, warum ...
command >file 2>&1
... ist nicht dasselbe wie ...
command 2>&1 >file
Der erste sendet beide Streams an file
, der zweite sendet Fehler an stdout
und die normale Ausgabe an file
.
Vorausgesetzt, dass /foo
nicht auf Ihrem System vorhanden ist und /tmp
…
$ ls -l /tmp /foo
druckt den Inhalt von /tmp
und druckt eine Fehlermeldung für /foo
$ ls -l /tmp /foo > /dev/null
sendet den Inhalt von /tmp
an /dev/null
und druckt eine Fehlermeldung für /foo
$ ls -l /tmp /foo 1> /dev/null
wird genau das gleiche tun (beachten Sie die 1)
$ ls -l /tmp /foo 2> /dev/null
druckt den Inhalt von /tmp
und sendet die Fehlermeldung an /dev/null
$ ls -l /tmp /foo 1> /dev/null 2> /dev/null
sendet sowohl die Auflistung als auch die Fehlermeldung an /dev/null
$ ls -l /tmp /foo > /dev/null 2> &1
ist Kurzschrift
Leute, denkt immer an den Hinweis von paxdiablo über die aktuelle Position des Umleitungsziels ... Es ist wichtig.
Meine persönliche Kurzbezeichnung für den Operator 2>&1
lautet:
&
als 'and'
oder 'add'
vor (das Zeichen ist ein Amper - und , nicht wahr?)2
(stderr) zu wo 1
(stdout) bereits/aktuell ist und add beide Streams' .Dieselbe Mnemonik funktioniert auch für die andere häufig verwendete Umleitung, 1>&2
:
&
, was and
oder add
bedeutet ... (Sie haben die Idee über das kaufmännische Und, ja?)1
(stdout) zu wo 2
(stderr) bereits/aktuell ist und add beide Streams' .Und denken Sie immer daran: Sie müssen Umleitungsketten "vom Ende" von rechts nach links lesen (nicht von links nach rechts).
Dies ist so, als würde man den Fehler an die Standardausgabe oder das Terminal weitergeben.
Das heißt, cmd
ist kein Befehl:
$cmd 2>filename
cat filename
command not found
Der Fehler wird folgendermaßen an die Datei gesendet:
2>&1
Standardfehler wird an das Terminal gesendet.
Eingabe umleiten
Die Umleitung der Eingabe bewirkt, dass die Datei, deren Name sich aus der Erweiterung von Word ergibt, zum Lesen im Dateideskriptor n oder in der Standardeingabe (Dateideskriptor 0) geöffnet wird, wenn n nicht angegeben ist.
Das allgemeine Format zum Umleiten von Eingaben lautet:
[n]<Word
Ausgabe umleiten
Die Umleitung der Ausgabe bewirkt, dass die Datei, deren Name sich aus der Erweiterung von Word ergibt, zum Schreiben in den Dateideskriptor n oder in die Standardausgabe (Dateideskriptor 1) geöffnet wird, wenn n nicht angegeben ist. Wenn die Datei nicht existiert, wird sie erstellt. Wenn es existiert, wird es auf die Größe Null gekürzt.
Das allgemeine Format zum Umleiten der Ausgabe lautet:
[n]>Word
Verschieben von Dateideskriptoren
Der Umleitungsoperator,
[n]<&digit-
verschiebt die Dateideskriptor-Ziffer in den Dateideskriptor n oder in die Standardeingabe (Dateideskriptor 0), wenn n nicht angegeben ist. Die Ziffer wird geschlossen, nachdem sie auf n dupliziert wurde.
Ebenso der Umleitungsoperator
[n]>&digit-
verschiebt die Dateideskriptor-Ziffer in den Dateideskriptor n oder in die Standardausgabe (Dateideskriptor 1), wenn n nicht angegeben ist.
man bash
Geben Sie /^REDIRECT
ein, um zum Abschnitt redirection
zu gelangen, und erfahren Sie mehr ...
Eine Online-Version finden Sie hier: .6 Weiterleitungen
Die meiste Zeit war man
das mächtige Werkzeug, um Linux zu lernen.
0 für die Eingabe, 1 für stdout und 2 für stderr.
Ein Tipp: somecmd >1.txt 2>&1
ist richtig, während somecmd 2>&1 >1.txt
völlig falsch ist, ohne Wirkung!