Warum Ausgabe nach 2> & 1 und 1> & 2 umleiten?

36

Ich bin auf mehrere Befehle gestoßen, die 2>&1und verwenden 1>&2, aber ich kann mich nicht mit dem Zweck der Verwendung und dem Zeitpunkt, zu dem ich sie verwenden sollte, auseinandersetzen.

Was ich verstehe

Ich weiß, dass 1das Standard aus und 2Standardfehler darstellt. Ich verstehe, dass 2>&1die Ausgabe von 2zu 1und umgekehrt kombiniert .

Was ich nicht verstehe

  1. Wann sollte ich es benutzen?
  2. Welchem ​​Zweck dient es?
PeanutsMonkey
quelle

Antworten:

39

Manchmal möchten Sie sowohl stdout als auch stderr an denselben Speicherort umleiten. In diesem Fall >&wird ein Dateideskriptor auf einen anderen verwiesen.


Wenn Sie beispielsweise sowohl stdout als auch stderr in dieselbe Datei schreiben möchten (sei es /dev/nulloder output.txt), können Sie sie separat mit umleiten

app 1>/dev/null 2>/dev/null

Oder Sie können einen Dateideskriptor in die Datei umleiten und den anderen in den ersten:

app 1>/dev/null 2>&1

app 2>/dev/null 1>&2

Im ersten Beispiel 2>&1zeigt der Dateideskriptor Nr. 2 auf die Stelle, auf die Nr. 1 bereits zeigt. Das zweite Beispiel erreicht dasselbe, indem es stattdessen mit stderr beginnt.

Als weiteres Beispiel gibt es Fälle, in denen stdout (Dateideskriptor Nr. 1) bereits auf den gewünschten Speicherort verweist, Sie jedoch nicht namentlich darauf verweisen können (dies kann mit einer Pipe, einem Socket oder dergleichen verbunden sein). Dies ist häufig der Fall, wenn Sie die Prozesserweiterung (die Operatoren ` `oder $( )) verwenden, mit der normalerweise nur stdout erfasst wird. Möglicherweise möchten Sie jedoch stderr einbeziehen. In diesem Fall würden Sie auch >&stderr auf stdout zeigen:

out=$(app 2>&1)

Ein weiteres häufiges Beispiel ist ein Pager grepoder ein ähnliches Dienstprogramm. Da die Pipe |normalerweise nur auf stdout funktioniert, würden Sie stderr vor der Verwendung der Pipe auf stdout umleiten:

app 2>&1 | grep hello

Wie kann man wissen, von welchem 2>&1oder 1>&2was richtig ist? Der bereits eingerichtete Dateideskriptor befindet sich rechts von >&und der Dateideskriptor, den Sie umleiten möchten, befindet sich links von. ( 2>&1bedeutet "Punktdateideskriptor # 2 bis Dateideskriptor # 1".)


Einige Shells verfügen über Verknüpfungen für allgemeine Umleitungen. Hier sind Beispiele von Bash:

  • 1> kann auf gerade gekürzt werden >

  • 1>foo 2>&1zu >&foooder&>foo

  • 2>&1 | program zu |& program

Grawity
quelle
Ich hatte keine Ahnung, dass dies app 1>/dev/null 2>&1bedeuten würde, dass 2> & 1 auf die Datei verweisen würde, zu der 1 bereits umgeleitet hat. Ich nehme an, ich könnte es genauso leicht tun app > /dev/null &>?
PeanutsMonkey
Es fällt mir schwer zu verstehen the already set up fd goes to the right of >&, and the fd you want to redirect goes to the left. Was meinst du mit dem bereits eingerichteten Dateideskriptor? Was bedeutet es, das Recht von?
PeanutsMonkey
Es tut mir leid, es sei denn, Sie wollten mir Anweisungen beibringen. Ich folge nicht der zuvor gemachten Aussage.
PeanutsMonkey
1
Nehmen Sie jede Dateideskriptorumleitung einzeln von links nach rechts und wenden Sie diese Regeln in dieser Reihenfolge an. Wenn Sie erste direkte stdout in eine Datei, dann Umleitung stderr, wo stdout uns jetzt zeigen, dann stderr und stdout wird auf die gleiche Datei gehen. Wenn Sie diese beiden Umleitungen vertauscht haben, erhalten Sie unterschiedliche Ergebnisse (leiten Sie stderr dorthin um, wo stdout jetzt abläuft , und verschieben Sie stdout dorthin , um auf eine andere Datei zu verweisen, während stderr dorthin weiterläuft, wo auf die Datei verwiesen wurde).
Jason
2

Eine Situation, die Sie benötigen, ist, wenn Sie die straceAusgabe in einem Pager anzeigen möchten . stracedruckt Standard seines Ausgangsfehler und Leitungen im Allgemeinen Standard verbindet Ausgang der Standardeingabe, so dass Sie die Umleitung verwenden:

strace -p $pid 2>&1 | less
jpalecek
quelle
Was meinst du damit pipes generally connect standard output to standard input?
PeanutsMonkey
2
Ich meine, dass pipe ( |) die Standardausgabe des ersten Befehls nimmt und sie mit der Standardeingabe des zweiten Befehls verbindet.
Jpalecek
2

Manchmal möchten Sie sowohl stdout( 1) als auch stderr( 2) an denselben Speicherort umleiten ( /dev/nullz. B.). Ein Weg, dies zu erreichen, wäre:

$ program 1>/dev/null 2>/dev/null

Aber die meisten Menschen verkürzen dies durch Umleitung stderrauf stdoutmit 2>&1:

$ program 1>/dev/null 2>&1

Eine noch kürzere Version ist:

$ program >&- 2>&-
Zaz
quelle
1

2: Dies ist der Fall, wenn die Ausgabe sowohl von Standardfehlern als auch von Standardausgängen stammen soll und Sie möchten, dass sie zu einer einzelnen Zeichenfolge zusammengefasst werden.

1: Wenn Sie die Ausgabe von Standardfehler und Standardausgang bearbeiten möchten.

soandos
quelle
Was meinst du mit manipulieren? Ich verstehe, dass alles, zu dem umgeleitet >2wird, an / dev / null gesendet wird. Oder habe ich mich völlig geirrt?
PeanutsMonkey
Das ist nicht richtig. Mit manipulieren meine ich "Pipe it to grep" oder ähnliches. Sehen Sie hier ein Beispiel.
Soandos
0

Ich benutze es, um einen freistehenden Job zu starten:

someProgram 2>&1 >& my.log &

dann kann ich mich abmelden und someProgram läuft noch. Die Funktionalität wird von GNU Screen, tmux und einigen anderen Programmen bereitgestellt - hier wird sie jedoch ohne externe Abhängigkeiten erreicht.

Adobe
quelle
1
Das funktioniert nur, solange kein SIGHUP an das Programm gesendet wird. Besser nutzen nohupoder disownin solchen Fällen.
Slhck
@slhck: ok Aber wenn ich SIGHUP nicht zum Programm schicken würde - wird es niemand tun, oder?
Adobe
Nein, das steuernde Terminal warnt die Abmeldevorgänge mit SIGHUP. Wenn Sie in der Praxis eine Remote-Shell über SSH ausführen und beenden, stirbt beispielsweise auch Ihr Prozess ab.
Slhck
@slhck: Kann nicht wahr sein: Ich benutze es seit ein paar Jahren - ich logge mich von ssh aus und der Prozess läuft noch.
Adobe
Ich muss das genauer nachschlagen, aber es hat nicht in allen Fällen geklappt, Programme in den Hintergrund zu stellen, und es funktioniert definitiv nicht einmal auf meinem lokalen Computer. Zsh und Bash verhalten sich offenbar auch hier anders.
Slhck
0

Stellen Sie sich vor, es gibt ein Verzeichnis trymit den folgenden drei Dateien:file file1 and file2.

Führen Sie nun diesen Befehl aus:

cat file file1 file2 file3

Die ersten drei Dateien werden geöffnet, aber catbeim Öffnen der vierten Datei tritt ein Fehler auf, da diese nicht vorhanden ist.

Führen Sie nun Folgendes aus:

cat file file1 file2 file3 1>outfile 2>&1

Sie werden keine Ausgabe auf dem Bildschirm sehen: Erstens 1>outfilewird die Ausgabe des Befehls an outfileumgeleitet , und dann wird 2>&1der Fehler, der beim Öffnen file3von ausgegeben wurde, umgeleitet ( ) outfile.

1>&2 Funktioniert ähnlich und leitet den Fehlerstrom zur Standardausgabe um.

Hoffe das hilft!

Faiz
quelle
0

Alternatives Szenario: Terminalbefehle zeigen die Ausgabe in einem anderen Terminal an

Verwenden Sie den ttyBefehl in jedem Terminal, um sie zu identifizieren:

$ tty
/dev/pts/0

$ tty
/dev/pts/1

Unter der Annahme, dass diese TTYs die Standardausgabe der ersten auf die zweite umleiten, führen Sie diese im ersten Terminal aus:

exec 1>/dev/pts/1

Hinweis: Jetzt wird jede Befehlsausgabe auf pts / 1 angezeigt

So stellen Sie das Standardverhalten stdout von pts / 0 wieder her:

exec 1>/dev/pts/0

In diesem Video sehen Sie eine Demonstration.

Vitalie Ghelbert
quelle
0

Der Fall, dass stderr auf stdout umgeleitet wird, wurde hier bereits behandelt (z. B. um Fehlermeldungen (grep) zu filtern).

Der andere Fall ist die Umleitung von stdout nach stderr. Ein häufiger Anwendungsfall (zumindest für mich) ist das Senden von Warnungen / Fehlermeldungen, die mit "Echo" (in meinen Shellscripts) gedruckt sind, an den stderr (damit sie die Aufmerksamkeit des Benutzers leichter auf sich ziehen können).

Beispielsweise,

echo "file \"${file\" does not exist..." 1>&2
umläute
quelle