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

21

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

Eigentlich möchte ich wissen, wie man zuverlässig die gesamte Programmausgabe erfasst, egal welchen "Stream" er verwendet. Das Problem, das ich habe, ist, dass einige Programme ihre Ausgabe nicht erfassen zu lassen 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 wird die Ausgabe beide Male angezeigt? Ich habe erwartet, dass alles nach / dev / null geleitet wird .

Welchen Ausgabestream verwendet die Zeit und wie kann ich ihn 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 'time' auf die richtige Weise erfasst werden:

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

(keine Ausgabe wird gesehen - richtig)

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

Will Sheppard
quelle
3
zuerst sollten Sie die Reihenfolge umkehren: 2>&1 > /dev/nullMittel „2 geht nun an , wo 1 geht (dh das Terminal, in der Standardeinstellung), und dann 1 jetzt geht an / dev / null (aber 2 geht noch zum Terminal!) verwenden. >/dev/null 2>&1sagen "1 geht jetzt nach / dev / null, dann geht 2 dorthin, wo 1 geht (dh auch nach / dev / null). Dies funktioniert hier immer noch nicht, da die eingebaute 'Zeit' nicht umgeleitet wird, aber im Allgemeinen korrekt ist (zum Beispiel würde es funktionieren, wenn Sie / usr / bin / time verwenden). Stellen Sie sich "2> & 1" vor, als würde die "Richtung" von 1 in 2 kopiert, nicht als "Gehe zu 1"
Olivier Dulac,

Antworten:

38

Diese Frage wird in BashFAQ / 032 angesprochen . 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, die Sie wollen , werden timeden Befehl sleep 1 2>/dev/null(ja, der Befehl sleep 1mit stderr umgeleitet /dev/null). Das Builtin timefunktioniert so, dass dies tatsächlich möglich ist.

Der bash Builtin kann dies tatsächlich tun, weil ... nun, es ist ein Builtin. Ein solches Verhalten wäre mit dem 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 Ihre Frage

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

Ist dies der Fall, geht die Ausgabe zu stdout oder stderr .

Hoffe das hilft!

gniourf_gniourf
quelle
2
gehen Sie können anderen fd erstellen und Befehle haben explizit die (zB: in Bash - Skript: exec 3>/some/file ; ls >&3 ;)
Olivier Dulac
@OlivierDulac Klar, oder noch einfacher mit dem coproceingebauten. Beim timeeingebauten ist dies jedoch nicht der Fall .
gniourf_gniourf
@ gniourf-gniourf: Ich kommentierte wegen Ihres Satzes "die Ausgabe geht an stdout oder stderr" ^^
Olivier Dulac
14

Ihre spezielle Frage zu timebuiltin wurde beantwortet, aber es gibt einige Befehle, die weder nach stdoutnoch nach schreiben stderr. Ein klassisches Beispiel ist der Unix-Befehl crypt. cryptOhne Argumente werden Standardeingaben verschlüsselt stdinund in die Standardausgabe geschrieben stdout. Es fordert den Benutzer zur Eingabe eines Kennworts auf getpass(), das standardmäßig eine Eingabeaufforderung für ausgibt /dev/tty. /dev/ttyist das aktuelle Endgerät. Schreiben auf /dev/ttybewirkt, dass in das aktuelle Terminal geschrieben wird (falls vorhanden, siehe isatty()).

Der Grund, warum cryptnicht in geschrieben werden kann, stdoutist, dass verschlüsselte Ausgaben in geschrieben werden stdout. Es ist auch besser, aufzufordern, /dev/ttyanstatt zu schreiben, stderrdamit die Aufforderung weiterhin angezeigt wird , wenn ein Benutzer auf stdoutund umleitet stderr. (Aus dem gleichen Grund cryptkann das Kennwort nicht gelesen werden stdin, da es zum Lesen der zu verschlüsselnden Daten verwendet wird.)

Alok
quelle
2
+1. Weniger relevant für das OP, aber relevanter für alle, die darauf stoßen "Warum wird die Ausgabe einiger Linux-Programme weder an STDOUT noch an STDERR gesendet?" über Google. :-)
Ruakh
0

time sleep 1 > /dev/null 2>&1# leitet die Ausgabe von "sleep" um do null. Dann schreibt "time" seine eigene Ausgabe ohne Umleitung. Es ist wie " time (sleep 1 > /dev/null 2>&1)".

(time sleep 1) > /dev/null 2>&1 # führt "Zeitschlaf 1" aus und leitet dann seine Ausgabe auf null um.

[] s

Márcio
quelle
-1

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 /dev/nullund der Standardfehler an die Standardausgabe weitergeleitet.

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) zu umgeleitet /dev/null.

Uwe Plonus
quelle
Dies funktioniert nicht mit der eingebauten Bash time. Siehe meine Antwort für einige Erklärungen.
gniourf_gniourf
+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