3178 Stimmen

Was bedeutet in der Shell "2>&1"?

Wenn ich in einer Unix-Shell Folgendes kombinieren möchte stderr y stdout in die stdout stream für weitere Manipulationen kann ich am Ende meines Befehls folgendes anhängen:

2>&1

Wenn ich also Folgendes verwenden möchte head auf die Ausgabe von g++ kann ich so etwas tun:

g++ lots_of_errors 2>&1 | head

so dass ich nur die ersten paar Fehler sehen kann.

Ich habe immer Schwierigkeiten, mir das zu merken, und muss es immer wieder nachschlagen, vor allem, weil ich die Syntax dieses speziellen Tricks nicht ganz verstehe.

Kann jemand das aufschlüsseln und Zeichen für Zeichen erklären, was 2>&1 bedeutet?

63 Stimmen

@dbr Ich glaube nicht, dass es nur an der Bash liegt - ich glaube, es ist eine Sache der Bourne-Shell; daher sh, bash, ksh, ash, dash, usw.

8 Stimmen

Dies ist Teil des Umleitungsparagraphen, der POSIX-konforme Shells oder kurz POSIX-Shells beschreibt. ksh ist zum Beispiel eine POSIX-Shell. Siehe: pubs.opengroup.org/onlinepubs/009695399/utilities/

19 Stimmen

Dieses Konstrukt funktioniert auch unter Windows.

3570voto

Ayman Hourieh Punkte 122012

Dateideskriptor 1 ist die Standardausgabe ( stdout ).
Dateideskriptor 2 ist der Standardfehler ( stderr ).

Es gibt eine Möglichkeit, sich dieses Konstrukt zu merken (auch wenn es nicht ganz korrekt ist): am Anfang, 2>1 mag eine gute Möglichkeit zur Umlenkung sein stderr a stdout . Sie wird jedoch tatsächlich als "Umleitung" interpretiert. stderr in eine Datei namens 1 ". & zeigt an, dass es sich bei dem, was folgt und vorangeht, um einen Dateideskriptor und nicht um einen Dateinamen handelt. So wird das Konstrukt: 2>&1 .

Erwägen Sie >& als Betreiber der Redirect Fusion.

1 Stimmen

Ergibt das einen Sinn für Sie? java... 2&1 >> data.log Ich habe gesehen, dass einer meiner Kollegen das getan hat?

3 Stimmen

>> bedeutet, dass die Ausgabe an die Datei data.log angehängt wird.

3 Stimmen

@ThangPham meinen STDOUT angehängt an data.log STDERR wird auf STDOUT ausgegeben (Konsole oder nächster Befehl) siehe meine Antwort

1006voto

dbr Punkte 158949
echo test > afile.txt

leitet stdout um nach afile.txt . Dies ist dasselbe wie das

echo test 1> afile.txt

Um stderr umzuleiten, tun Sie das:

echo test 2> afile.txt

Así que >& ist die Syntax für umleiten a Strom zum anderen Dateideskriptor :

  • 0 ist stdin
  • 1 ist stdout
  • 2 ist stderr

Sie können stdout nach stderr umleiten, indem Sie dies tun:

echo test 1>&2 # or echo test >&2

Oder andersherum:

echo test 2>&1

Also, kurz gesagt... 2> leitet stderr in eine (nicht spezifizierte) Datei um und fügt &1 leitet stderr nach stdout um.

6 Stimmen

Ergibt das einen Sinn für Sie? java ... 2&1 >> data.log Ich habe gesehen, dass einer meiner Kollegen das getan hat?

7 Stimmen

@Harry das sieht entweder nach einer Shell aus, die nicht Bash ist, oder nach einem Tippfehler. cmd 2>&1 >> somefile.log fügt stdout/stderr an eine Datei an - es ist im Grunde dasselbe wie oben, mit >> file zum Anhängen

116 Stimmen

@dbr cmd 2>&1 >>file leitet stderr nicht in die Datei um, sondern cmd >> file 2>&1 tut. Die Reihenfolge ist wichtig. Im ersten Fall wird stderr zum stdout der Shell umgeleitet (möglicherweise ein tty, wenn der Befehl interaktiv eingegeben wird), und dann wird stdout in die Datei geleitet. Im zweiten Fall wird stdout an die Datei und dann stderr an dieselbe Stelle geleitet.

434voto

F. Hauri Punkte 57640

Einige Tricks zur Weiterleitung

Einige Syntaxbesonderheiten können dabei wichtige Verhaltensweisen haben. Es gibt einige kleine Beispiele für Umleitungen, STDERR , STDOUT und Argumente Bestellung .

1 - Überschreiben oder Anhängen?

Symbol > bedeutet Nachsendung .

  • > bedeutet als ganze abgeschlossene Datei zu senden und überschreibt das Ziel, falls vorhanden (siehe noclobber bash-Funktion unter #3 später).
  • >> bedeutet senden zusätzlich zu würde an das Ziel angehängt, falls vorhanden.

In jedem Fall würde die Datei erstellt werden, wenn sie nicht existiert.

2 - Die Shell-Befehlszeile ist auftragsabhängig!!

Um dies zu testen, benötigen wir ein einfacher Befehl, der auf beiden Ausgängen etwas ausgibt :

$ 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 namens /tnt natürlich ;). Nun, wir haben es!!

Also, schauen wir mal:

$ 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 speichert STDERR auf der Konsole, und es scheint nicht das erwartete Verhalten zu sein... Aber...

Wenn Sie etwas machen wollen Nachfilterung über Standard Ausgabe, error Ausgabe oder beides:

$ 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 im vorherigen Absatz, wo ich schrieb scheinen nicht das erwartete Verhalten zu sein (dies könnte also sogar ein erwartetes Verhalten sein).

Nun, es gibt einen kleinen Trick bei Weiterleitungen, denn verschiedene Operationen an beiden Ausgängen durchfü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

Nota : &9 Deskriptor würde spontan auftreten, weil ) 9>&2 .

Nachtrag: nota! Mit der neuen Version von bash ( >4.0 ) gibt es eine neue Funktion und eine attraktivere Syntax für diese Art von Aufgaben:

$ 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 schließlich 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! Dieselbe neue Syntax, in beiden Fällen:

$ 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

Wo STDOUT durch einen speziellen Filter laufen, STDERR zu einem anderen und schließlich durchlaufen die beiden zusammengefassten Ausgaben einen dritten Befehlsfilter.

2b - Verwendung |& stattdessen

Syntax command |& ... könnte als alias para command 2>&1 | ... . Für die Befehlszeilenreihenfolge gelten dieselben Regeln. Mehr Details unter Was ist die Bedeutung des Operators |& in der Bash?

3 - Ein Wort zu noclobber Option und >| Syntax

Das ist ungefähr Überschreiben :

Während set -o noclobber die Bash anweisen no eine bestehende Datei überschreiben, wird die >| Syntax können Sie diese Beschränkung überwinden:

$ 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 jedes Mal überschrieben, also jetzt:

$ 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

Durchgang 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, ob sie bereits aktiviert ist.

$ 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

4 - Letzter Trick und mehr...

Zur Umleitung beide Ausgabe eines bestimmten Befehls, sehen wir, dass eine richtige Syntax sein könnte:

$ ls -ld /tmp /tnt >/dev/null 2>&1

für diese Spezial Fall gibt es eine Abkürzungssyntax: &> ... oder >&

$ ls -ld /tmp /tnt &>/dev/null

$ ls -ld /tmp /tnt >&/dev/null

Anmerkung: Wenn 2>&1 existieren, 1>&2 ist ebenfalls eine korrekte Syntax:

$ ls -ld /tmp /tnt 2>/dev/null 1>&2

4b- Nun, ich lasse Sie darüber nachdenken:

$ 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/

4c- Wenn Sie interessiert sind an mehr Informationen

Sie können das ausführliche Handbuch lesen, indem Sie auf klicken:

man -Len -Pless\ +/^REDIRECTION bash

in einem bash Konsole ;-)

6 Stimmen

Lesen Sie weiter: Wenn Ihnen das gefallen hat, gefällt es Ihnen vielleicht auch: Wie Umleitungsmissbrauch zu seltsamen Verhaltensweisen führen kann

1 Stimmen

0 Stimmen

Das ist die beste Antwort, und wirklich cool.

193voto

Deen John Punkte 2948

Ich habe diesen brillanten Beitrag über die Weiterleitung gefunden: Alles über Umleitungen

Standardausgabe und Standardfehler in eine Datei umleiten

$ Befehl &>Datei

Dieser Einzeiler verwendet die &> Operator, um beide Ausgabeströme - stdout und stderr - vom Befehl in eine Datei umzuleiten. Dies ist die Abkürzung der Bash, um beide Ströme schnell an dasselbe Ziel umzuleiten.

So sieht die Dateideskriptor-Tabelle aus, nachdem die Bash die beiden Streams umgeleitet hat:

Enter image description here

Wie Sie sehen können, zeigen sowohl stdout als auch stderr jetzt auf file . Alles, was in stdout und stderr geschrieben wird, wird also in file .

Es gibt mehrere Möglichkeiten, beide Streams an dasselbe Ziel umzuleiten. Sie können jeden Stream nacheinander umleiten:

$ Befehl >Datei 2>&1

Dies ist ein weitaus häufigerer Weg, um beide Streams in eine Datei umzuleiten. Zuerst wird stdout in eine Datei umgeleitet und dann wird stderr so dupliziert, dass es dasselbe ist wie stdout. So zeigen beide Ströme am Ende auf file .

Wenn die Bash mehrere Umleitungen sieht, verarbeitet sie diese von links nach rechts. Gehen wir die Schritte durch, um zu sehen, wie das geschieht. Bevor irgendwelche Befehle ausgeführt werden, sieht die Dateideskriptor-Tabelle der Bash wie folgt aus:

Enter image description here

Jetzt verarbeitet die Bash die erste Umleitungsdatei. Wir haben das schon einmal gesehen und es lässt stdout auf file zeigen:

Enter image description here

Als nächstes sieht Bash die zweite Umleitung 2>&1. Wir haben diese Umleitung noch nicht gesehen. Diese dupliziert den Dateideskriptor 2 zu einer Kopie des Dateideskriptors 1 und wir erhalten:

Enter image description here

Beide Streams wurden in eine Datei umgeleitet.

Seien Sie hier jedoch vorsichtig! Schreiben

Befehl >Datei 2>&1

ist nicht dasselbe wie Schreiben:

$ Befehl 2>&1 >Datei

Die Reihenfolge der Umleitungen ist in der Bash wichtig! Mit diesem Befehl wird nur die Standardausgabe in die Datei umgeleitet. Der stderr wird weiterhin auf dem Terminal ausgegeben. Um zu verstehen, warum das so ist, gehen wir die Schritte noch einmal durch. Bevor der Befehl ausgeführt wird, sieht die Dateideskriptor-Tabelle wie folgt aus:

Enter image description here

Jetzt verarbeitet die Bash Umleitungen von links nach rechts. Sie sieht zuerst 2>&1, also dupliziert sie stderr nach stdout. Die Dateideskriptor-Tabelle wird:

Enter image description here

Jetzt sieht Bash den zweiten Redirect, >file und leitet stdout in eine Datei um:

Enter image description here

Verstehen Sie, was hier passiert? Stdout zeigt jetzt auf eine Datei, aber stderr zeigt immer noch auf das Terminal! Alles, was in stderr geschrieben wird, wird immer noch auf dem Bildschirm ausgegeben! Seien Sie also sehr, sehr vorsichtig mit der Reihenfolge der Redirects!

Beachten Sie auch, dass in der Bash das Schreiben von

$ Befehl &>Datei

ist genau dasselbe wie:

$ Befehl >&Datei

5 Stimmen

Die letzten beiden unterscheiden sich, wenn "command" auf eine Zahl endet, denn dann wird dies als optionaler Dateideskriptor für >&

0 Stimmen

Sehr schöne Zeichnung und Erklärung! Könnten Sie näher erläutern, was "duplizieren" wirklich bedeutet? Sie erwähnten: "Dieser [2>&1] dupliziert den Dateideskriptor 2 als Kopie des Dateideskriptors 1". Das klingt, als ob stderr nach stdout dupliziert wird. Aber wenn das der Fall ist, sollte ich auch err sehen, obwohl /dev/tty0 ?

3 Stimmen

Das ist eine sehr schöne Erklärung mit Bildmaterial. Wenn ich derjenige bin, der diese Frage stellt, werde ich dies als akzeptierte Antwort markieren.

130voto

Colin Burnett Punkte 10609

Die Zahlen beziehen sich auf die Dateideskriptoren (fd).

  • Null ist stdin
  • Eine ist stdout
  • Zwei ist stderr

2>&1 leitet fd 2 auf 1 um.

Dies funktioniert für eine beliebige Anzahl von Dateideskriptoren, wenn das Programm sie verwendet.

Sie können sich ansehen /usr/include/unistd.h wenn Sie sie vergessen:

/* 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 standardisierte Dateideskriptoren für benutzerdefinierte Protokollierung verwenden, so dass Sie es nicht sehen, es sei denn, Sie leiten es in eine Datei oder etwas anderes um.

1 Stimmen

Ist es in Ordnung, wenn Sie Ihre eigenen "Nicht-Standard-Dateideskriptoren" verwenden? Woher wissen Sie, dass es keine offene Datei mit demselben FD gibt?

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X