Unterschied zwischen 2> & 1> output.log und 2> & 1 | tee output.log

35

Ich wollte den Unterschied zwischen den folgenden zwei Befehlen kennen

2>&1 > output.log 

und

2>&1 | tee output.log

Ich habe gesehen, wie einer meiner Kollegen die zweite Option zum Weiterleiten verwendet hat. Ich weiß, was 2> & 1 macht. Meine einzige Frage ist, wozu tee verwendet werden soll, wenn ein einfacher Umleitungsoperator ">" verwendet werden kann.

Chander Shivdasani
quelle

Antworten:

11

Betrachten Sie die beiden Befehle getrennt:

utility 2>&1 >output.log 

Da hier Umleitungen von links nach rechts verarbeitet werden, wird der Standardfehlerstrom zuerst an die Stelle umgeleitet, an der sich der Standardausgabestream befindet (möglicherweise an die Konsole), und dann wird der Standardausgabestream in eine Datei umgeleitet. Der Standardfehlerstrom würde nicht in diese Datei umgeleitet.

Der sichtbare Effekt davon wäre, dass Sie das erhalten, was bei Standardfehlern auf dem Bildschirm erzeugt wird und was bei Standardausgaben in der Datei erzeugt wird.

utility 2>&1 | tee output.log

Hier leiten Sie Standardfehler an dieselbe Stelle um wie den Standardausgabestream. Dies bedeutet, dass beide Streams teeals ein einziger vermischter Ausgabestream an das Dienstprogramm weitergeleitet werden und dass diese Standardausgabedaten in der angegebenen Datei von gespeichert werden tee. Die Daten würden zusätzlich von teein der Konsole reproduziert (dies ist, was teees Datenströme dupliziert).

Welche davon verwendet wird, hängt davon ab, was Sie erreichen möchten.

Beachten Sie, dass Sie den Effekt der zweiten Pipeline nicht einfach reproduzieren können >(wie in utility >output.log 2>&1, wodurch sowohl die Standardausgabe als auch der Fehler in der Datei gespeichert werden). Sie müssten verwenden tee, um die Daten sowohl in der Konsole als auch in der Ausgabedatei abzurufen.


Zusätzliche Bemerkungen:

Der sichtbare Effekt des ersten Befehls,

utility 2>&1 >output.log 

wäre das gleiche wie

utility >output.log

Dh die Standardausgabe geht in die Datei und der Standardfehler geht in die Konsole.

Wenn am Ende jedes der obigen Befehle ein weiterer Verarbeitungsschritt hinzugefügt würde, würde dies jedoch einen großen Unterschied bedeuten:

utility 2>&1 >output.log | more_stuff

utility >output.log      | more_stuff

In der ersten Pipeline wird more_stuffder ursprüngliche Standardfehlerstrom utilityals Standardeingabedaten abgerufen, während in der zweiten Pipeline der more_stuffTeil der Pipeline nichts erhält , da nur der resultierende Standardausgabestrom jemals über eine Pipe gesendet wird auf seiner Standardeingabe zu lesen.

Kusalananda
quelle
utility 2>&1 | tee output.logWollen Sie mit dem Befehl " sagen, dass 1 an tee gerichtet ist, 2 auch. Da tee den Stream dupliziert, wird die Ausgabe sowohl auf der Konsole angezeigt als auch in eine Datei geschrieben? Daher der Unterschied zwischen utility 2>&1 > output.logund utility 2>&1 | tee output.logliegt daran, teedass es den Stream dupliziert. Wäre das richtig?
Motiviert
Mit den Beispielen von utility 2>&1 > output.log | more_stuffund utility >ouput.log| more_stuff , is the difference that more_stuff` hat die Standardfehlerausgabe an die Konsole als Eingabe more_stuff? Da im zweiten Beispiel keine Ausgabe an die Konsole erfolgt, erfolgt im Wesentlichen keine Eingabe an more_stuff? Wenn ja, ist dies nicht klar, da Sie im vorhergehenden Absatz feststellen, dass die Standardausgabe in die Datei und der Standardfehler in die Konsole übertragen wird.
Motivierter
@Motivated Dein erster Kommentar scheint mir richtig zu sein, ja. Was den zweiten Kommentar betrifft: more_stuffWürde im ersten Befehl empfangen, was utilityursprünglich an seinen Fehlerstrom gesendet wurde (was aber zur Standardausgabe umgeleitet wurde). Nicht weil es auf der Konsole landen würde, wenn more_stuffes nicht da wäre, sondern weil es zum Standardausgabestream geht . more_stuffEmpfängt im zweiten Befehl nichts, da auf der linken Seite der Pipeline keine Standardausgabe vorhanden ist. Der Fehlerstrom von utilitywürde im 2. Befehl immer noch auf der Konsole landen.
Kusalananda
Vielen Dank. Meinen Sie das, weil der Befehl utility > output.log | more_stuffaus der Sicht eines Standardfehlers nicht zu einer Ausgabe im Standardausgabestream führt?
Motivierter
@Motivated Da die linke Seite bei der Standardausgabe nichts erzeugt (sie wird umgeleitet), werden keine Daten über die Pipe gesendet.
Kusalananda
24

Redaktioneller Hinweis

Bitte lesen Sie unbedingt die Kommentare zu dieser Antwort - derobert .


Ursprüngliche Antwort

2>&1 >output.logMittel beginnen zuerst alle Datei - Handle 2 stuff (Standardfehler) , um Datei - Handle 1 (Standardausgabe) sendet dann , dass die Datei senden output.log. Mit anderen Worten, senden Sie den Standardfehler und die Standardausgabe an die Protokolldatei.

2>&1 | tee output.logist dasselbe mit dem 2>&1Bit, es kombiniert Standardausgabe und Standardfehler zu dem Standardausgabestrom. Dann leitet es das teeProgramm weiter, das seine Standardeingabe an seine Standardausgabe (wie cat) und auch an die Datei sendet . Es kombiniert also die beiden Streams (Fehler und Ausgabe) und gibt diese dann an das Terminal und die Datei aus.

Unterm Strich ist , dass die erste sendet stderr/ stdoutin die Datei, während die zweite sendet sie an sowohl der Datei und die Standardausgabe (das ist wahrscheinlich das Terminal , wenn Sie in ein anderes Konstrukt sind die Standardausgabe umgeleitet wurde).

Ich erwähne diese letzte Möglichkeit, weil Sie Dinge haben können wie:

(echo hello | tee xyzzy.txt) >plugh.txt

wo nichts auf dem terminal landet.

derobert
quelle
13
-1 Sie haben die richtige Syntax, aber nicht die Semantik. Ausführen cat /doesnotexist 2>&1 >output.txt- Auf cat: /doesnotexist: No such file or directorydem Terminal wird angezeigt, und output.txt ist eine leere Datei. Rangfolge und Schließung sind im Spiel: 2>&1(dup fd2 vom aktuellen fd1), dann >output.txt(fd1 zur output.txt umleiten, nichts anderes ändern). Der Grund, der 2>&1 |anders ist, liegt in der Rangfolge: |vor >.
Arcege,
5
Diese Antwort ist grundsätzlich in jeder Hinsicht falsch . Viele der folgenden Antworten sind besser, aber ich denke, diese von Kusalananda ist die klarste.
Michael Homer
2
@ user14408: Sollten Sie jemals ein Konto bei Unix & Linux einrichten und diese Antwort anfordern , können Sie meinen redaktionellen Hinweis jederzeit entfernen, sobald Sie die Kommentare bearbeitet haben.
Derobert
8

Der erste Befehl erledigt die andere Aufgabe:

Nach

2>&1 > output.log 

Das alte STDOUT wird in STDERR gespeichert (kopiert) und dann wird STDOUT in die Datei umgeleitet.

Also, stdout geht zur Datei und stderr geht zur Konsole.

Und in

 2>&1 | tee output.log

Beide Streams werden auf tee umgeleitet. Tee dupliziert alle Eingaben in seine Standardausgabe (in Ihrem Fall in die Konsole) und in die Datei ( output.log).

Und es gibt eine andere Form von erstem:

    > output.log  2>&1

Dadurch werden sowohl STDOUT als auch STDERR in die Datei umgeleitet.

osgx
quelle
4

Ersteres wird nur in die Datei ausgegeben. Die zweite Ausgabe erfolgt sowohl in der Datei als auch auf dem Bildschirm.


quelle
4

Der Grund dafür 2>&1 | teeist, dass sowohl stdout als auch stderr in einer Protokolldatei erfasst und gleichzeitig auf dem Bildschirm angezeigt werden können. Dies könnte auch geschehen >output.txt 2>&1 & tail -f, aber Sie würden nicht wissen, wann der Befehl im Hintergrund beendet wurde - wird das Programm beendet oder wird es ohne Ausgabe ausgeführt? Das 2>&1 | teewar eine verbreitete Redewendung für Programmierer.

Arcege
quelle
Wollen Sie damit sagen, dass 2> & 1> file.txt beispielsweise nicht sowohl stdout als auch stderr in file.txt erfasst?
Motivierter
0

Sehen wir uns zuerst einen Beispielcode an:

#include <stdio.h>
main() 
{
// message 1, on stdout (using  printf)
printf("%s",          "message 1, on stdout (using  printf)\n");

// message 2, on stdout (using fprintf)
fprintf(stdout, "%s", "message 2, on stdout (using fprintf)\n");

// message 3, on stderr (using fprintf)
fprintf(stderr, "%s", "message 3, on stderr (using fprintf)\n");
}

Vergleichen wir die Ergebnisse:
./helloerror
+ Datei: keine Nachricht; Konsole: Nachricht 1,2,3;

./helloerror >error.txt
+ Datei: Nachricht 1,2; Konsole: Nachricht 3;

./helloerror 2>&1 >error.txt
+ Datei: Nachricht 1,2; Konsole: Nachricht 3;
+ wie ./helloerror> error.txt

./helloerror >error.txt 2>&1
+ Datei: Nachricht 3,1,2; Konsole: keine Nachricht;
+ beachte, dass die Reihenfolge 3 zuerst ist, dann 1, dann 2

./helloerror | tee error.txt 2>&1
+ Datei: Nachricht 1,2; Konsole: Nachricht 3,1,2;
+ beachte, dass die Reihenfolge 3 zuerst ist, dann 1, dann 2

./helloerror 2>&1 | tee error.txt
+ Datei: Nachricht 3,1,2; Konsole: Nachricht 3,1,2;

Zu verwenden:
./helloerror >error.txt 2>&1
-> wenn man alle (stdout + stderr) Nachrichten in der Datei haben möchte, aber nicht auf der Konsole gedruckt

./helloerror 2>&1 | tee error.txt
-> wenn man alle Nachrichten (stdout + stderr) in einer Datei haben und auf der Konsole ausdrucken möchte

Hari Perev
quelle
-1

Hier ist ein Beitrag mit einer Zusammenfassung der Unix-Ausgabestreams: http://www.devcodenote.com/2015/04/unix-output-streams.html

Ein Ausschnitt aus der Post:

Es gibt 3 Standardausgabestreams:

STDIN - Standard Input - Writes from an input device to the program
STDOUT - Standard Output - Writes program output to screen unless specified otherwise.
STDERR - Standard Error Output - Writes error messages. Also printed to the screen unless specified otherwise.
Abhishek Jain
quelle