So leiten Sie stderr ohne stdout

24

Wie leite ich den Standardfehlerstrom weiter, ohne den Standardausgangsstrom weiterzuleiten?

Ich weiß, dass dieser Befehl funktioniert, aber er schreibt auch den Standard aus.

Command 2>&1 | tee -a $LOG

Wie bekomme ich nur den Standardfehler?

Hinweis: Ich möchte, dass der stderr-Stream einfach in ein Protokoll geschrieben und sowohl stderr als auch stdout in die Konsole geschrieben wird.

Kreuz
quelle

Antworten:

26

Verwenden Sie dazu einen zusätzlichen Dateideskriptor, um zwischen stderr und stdout zu wechseln:

find /var/log 3>&1 1>&2 2>&3 | tee foo.file

Grundsätzlich funktioniert es, oder zumindest denke ich, wie folgt:
Die Umleitungen werden von links nach rechts ausgewertet.

3>&1 Erstellt einen neuen Dateideskriptor 3 als Duplikat (Kopie) von fd 1 (stdout).

1>&2 Mache stdout (1) zu einem Duplikat von fd 2 (stderr)

2>&3 Machen Sie fd 2, ein Duplikat (Kopie) von 3, das zuvor als Kopie von stdout erstellt wurde.

Jetzt sind also stderr und stdout vertauscht.

| tee foo.file tee dupliziert den Dateideskriptor 1, der zu stderr gemacht wurde.

Kyle Brandt
quelle
Oh, nicht mit ksh getestet, funktioniert aber mit bash ...
Kyle Brandt
Danke, funktioniert auch in ksh. Ich denke, die meisten Pipe- und Stream-Dinge sind Posix-Standard.
C. Ross
"Kopieren" ist nicht richtig - Siehe @ Guasqueños Antwort.
Kyle Brandt
Dies funktioniert auch in Windows mit tee.exeinstalliertem :)
Acorn
13

Kyles Unix / Linux-Befehl erledigt das Umschalten des STDERR mit dem STDOUT. Die Erklärung ist jedoch nicht ganz richtig. Die Umleitungsoperatoren kopieren oder duplizieren nicht, sondern leiten den Fluss nur in eine andere Richtung um.

Das Umschreiben von Kyles Befehl durch zeitweiliges Verschieben von 3> & 1 zum Ende würde das Verständnis des Konzepts erleichtern:

find /var/log  1>&2  2>&3  3>&1  

Auf diese Weise geschrieben, würde Linux einen Fehler anzeigen, da & 3 noch nicht existiert, da es vor 3> & 1 liegt. 3> Etwas ist eine Möglichkeit zu deklarieren (definieren), dass wir ein drittes Rohr verwenden, also muss es lokalisiert werden, bevor wir Wasser in dieses Rohr fließen lassen, zum Beispiel wie Kyle es geschrieben hat. Probieren Sie es einfach zum Spaß anders aus:

((echo "STD1";  anyerror "bbbb"; echo "STD2" ) 3>&1 4>&2 1>&4 2>&3) > newSTDOUT 2> newSTDERR

Es ist eine Schande, keine Möglichkeit zu haben, Kopien anzufertigen. Sie können Dinge wie "3> & 1 3> & 2" nicht im selben Befehl ausführen, da Linux nur den ersten Befehl verwendet, der gefunden wurde, und den zweiten Befehl schließt.

Ich habe (noch) keine Möglichkeit gefunden, sowohl den Fehler als auch die reguläre Ausgabe in eine Datei zu senden und auch eine Kopie des Fehlers mit einem Befehl an die Standardausgabe zu senden. Zum Beispiel habe ich einen Cron-Job, bei dem beide Ausgaben (Fehler und Standard) in eine Protokolldatei gehen sollen und der Fehler auch ausgeht, um eine E-Mail-Nachricht an meinen blackBerry zu senden. Ich kann es mit zwei Befehlen unter Verwendung von "tee" tun, aber der Fehler wird nicht in der richtigen Reihenfolge in der regulären Ausgabezeile in der Datei angezeigt. Dies ist die hässliche Art und Weise, wie ich das Problem gelöst habe:

((echo "STD1"; sdfr "bbbb"; echo "STD2" ) 3>&1 1>&2 2>&3 | tee -a log1 ) 2>> log1

Beachten Sie, dass ich log1 zweimal verwenden muss und in beiden Fällen das erste mit der Option "-a" für den Befehl "tee" und das zweite mit ">>" anhängen muss.

Wenn Sie eine Katze log1 machen, erhalten Sie Folgendes:

STD1
STD2
-bash: sdfr: command not found

Beachten Sie, dass der Fehler in der zweiten Zeile nicht wie gewünscht angezeigt wird.

Guasqueño
quelle
Geniale Korrektur!
Kyle Brandt
Aktivieren Sie zsh und die mult_iosOption (standardmäßig aktiviert), um eine FD mehrmals umleiten zu können.
Tom Hale
2

Laut der Manpage für ksh (pdksh) können Sie einfach Folgendes tun:

Befehl 2> & 1> / dev / null | cat-n

dh dup stderr nach stdout, stdout nach / dev / null umleiten, dann in 'cat -n' umleiten

Funktioniert mit pdksh auf meinem System:

$ errorecho () {echo "$ @"> & 2;}

$ errorecho foo
foo

$ errorecho foo> / dev / null # sollte immer noch angezeigt werden, auch wenn stdout umgeleitet wurde
foo

$ errorecho foo 2> & 1> / dev / null | cat-n
     1 foo
$   
cas
quelle
Funktioniert auch mit BusyBox
Udo G
1

Ich habe es laufen lassen, wie du es immer wolltest, da ich es auch brauchte und dein Kommando verfeinerte. jetzt funktioniert es bei mir korrekt mit bash 3.2 auf debian squeeze mit diesem

(echo "foo" 3>&1 1>&2 2>&3 | tee -a log1 ) 2>> log1 >> log2

Während log1 stdout und stderr protokolliert und log2 nur stderr protokolliert und nichts anderes auf dem Bildschirm anzeigt.

martinseener
quelle