Warum geht die Ausgabe einiger Linux-Programme weder an STDOUT noch an STDERR?

5699
Will Sheppard

Warum geht die Ausgabe einiger Linux-Programme weder an STDOUT noch an STDERR?

Eigentlich möchte ich wissen, wie ich zuverlässig alle Programmausgaben erfassen kann, unabhängig davon, welchen "Stream" es verwendet. Das Problem, das ich habe, ist, dass einige Programme ihre Ausgabe nicht zu erfassen scheinen.

Ein Beispiel ist der Befehl 'time':

time sleep 1 2>&1 > /dev/null  real 0m1.003s user 0m0.000s sys 0m0.000s 

oder

time sleep 1 &> /dev/null  real 0m1.003s user 0m0.000s sys 0m0.000s 

Warum sehe ich die Ausgabe beide Male? Ich habe erwartet, dass alles nach / dev / null geleitet wird .

Welchen Ausgabestrom verwendet die Zeit und wie kann ich diesen in eine Datei leiten?

Eine Möglichkeit, das Problem zu umgehen, besteht darin, ein Bash- Skript zu erstellen, das beispielsweise den folgenden combine.shBefehl enthält:

$@ 2>&1 

Dann kann die Ausgabe von 'Zeit' korrekt erfasst werden:

combine.sh time sleep 1 &> /dev/null 

(keine Ausgabe wird gesehen - korrekt)

Gibt es eine Möglichkeit, das zu erreichen, was ich möchte, ohne ein separates Kombinationsskript zu verwenden?

20
Zuerst sollten Sie die Reihenfolge umkehren: "2> & 1> / dev / null" bedeutet "2 geht jetzt dorthin, wo 1 geht (dh standardmäßig das Terminal), und dann 1 geht jetzt nach / dev / null (aber 2 noch immer) geht zum Terminal!). Verwenden Sie `> / dev / null 2> & 1`, um zu sagen" 1 geht jetzt nach / dev / null, dann 2 geht dorthin, wo 1 geht (dh auch nach / dev / null). Dies funktioniert auch hier nicht, da die eingebaute Zeit nicht umgeleitet wird, sie ist jedoch generell korrekt (z. B. würde sie funktionieren, wenn Sie / usr / bin / time verwenden). Denken Sie an "2> & 1", um die "Richtung" von 1 in 2 zu kopieren, nicht als 2, die zu 1 geht Olivier Dulac vor 10 Jahren 3

3 Antworten auf die Frage

38
gniourf_gniourf

Diese Frage wird in BashFAQ / 032 behandelt . In Ihrem Beispiel würden Sie:

{ time sleep 1; } 2> /dev/null 

Der Grund warum

time sleep 1 2>/dev/null 

nicht verhalten, wie Sie erwarten, weil mit dieser Syntax, werden Sie wollen timeden Befehl sleep 1 2>/dev/null(ja, der Befehl sleep 1mit stderr umgeleitet /dev/null). Das eingebaute timefunktioniert so, dass dies tatsächlich möglich ist.

Das bash Builtin kann dies tatsächlich, weil ... nun, es ist ein Builtin. Ein solches Verhalten wäre bei einem externen Befehl, der sich timenormalerweise in befindet, unmöglich /usr/bin. Tatsächlich:

$ /usr/bin/time sleep 1 2>/dev/null $ 

Nun die Antwort auf deine Frage

Warum geht die Ausgabe einiger Linux-Programme weder an STDOUT noch an STDERR?

ist: die Ausgabe geht nach stdout oder stderr .

Hoffe das hilft!

Sie können andere Fd-Dateien erstellen und Befehle explizit an diese übergeben (z. B .: in Bash-Skript: `exec 3> / some / file; ls> & 3;`). Olivier Dulac vor 10 Jahren 2
@OlivierDulac Sicher oder noch einfacher mit dem eingebauten `coproc`. Dies gilt jedoch nicht für die eingebaute "Zeit". gniourf_gniourf vor 10 Jahren 0
@ gniourf-gniourf: Ich kommentierte wegen deines Satzes "die Ausgabe geht nach stdout oder stderr" ^^ Olivier Dulac vor 10 Jahren 0
13
Alok

Ihre spezielle Frage zu timebuiltin beantwortet worden ist, aber es gibt einige Befehle, die entweder gar nicht schreiben stdoutoder zu stderr. Ein klassisches Beispiel ist der Unix-Befehl crypt. cryptohne Argumente verschlüsselt die Standardeingabe stdinund schreibt sie in die Standardausgabe stdout. Es fordert den Benutzer zur Verwendung eines Kennworts auf getpass(), das standardmäßig eine Eingabeaufforderung an ausgibt /dev/tty. /dev/ttyist das aktuelle Endgerät. Beim Schreiben /dev/ttywird auf das aktuelle Terminal geschrieben (falls vorhanden, siehe isatty()).

Der Grund, aus dem cryptnicht geschrieben werden kann, stdoutist, dass verschlüsselte Ausgaben in geschrieben werden stdout. Es ist auch besser, nicht zu /dev/ttyschreiben, sondern um Aufforderung zu lesen stderr, wenn ein Benutzer stdoutund umleitet stderr. (Aus demselben Grund cryptkann das Kennwort nicht gelesen werden stdin, da es zum Lesen der zu verschlüsselnden Daten verwendet wird.)

+1. Weniger relevant für das OP, aber relevanter für alle, die auf das Internet stoßen "Warum wird die Ausgabe einiger Linux-Programme weder an STDOUT noch an STDERR gesendet?" über Google. :-) ruakh vor 10 Jahren 1
-1
Uwe Plonus

Das Problem in Ihrem Fall ist, dass die Umleitung auf andere Weise funktioniert. Sie schrieben

time sleep 1 2>&1 > /dev/null 

Dadurch wird die Standardausgabe an die Standardausgabe /dev/nullund dann der Standardfehler umgeleitet.

Um alle Ausgaben umzuleiten, müssen Sie schreiben

time sleep 1 > /dev/null 2>&1 

Dann wird der Standardfehler zur Standardausgabe umgeleitet, und danach wird die gesamte Standardausgabe (die den Standardfehler enthält) umgeleitet /dev/null.

Dies funktioniert nicht mit der bash _builtin_ `time`. Siehe meine Antwort für einige Erklärungen. gniourf_gniourf vor 10 Jahren 0
+1, weil dies eine nützliche Antwort auf eine ähnliche Frage ist. Obwohl @Olivier es im Kommentar zur obigen Frage besser erklärt. Will Sheppard vor 9 Jahren 0