Feststellen, ob die Ausgabe eines Befehls oder Shell-Skripts stdout oder stderr ist


32

Nehmen wir an, ich führe einen Befehl oder ein Shell-Skript aus und bekomme eine Ausgabe. Wie kann man feststellen, ob die Ausgabe von stderroder stammt, ohne die Interna dieses Befehls oder Shell-Skripts zu kennen stdout?

Zum Beispiel

$ ls -ld /
drwxrwxr-t  35 root  admin  1258 Dec 11 19:16 /

vs

ls -ld /test
ls: /test: No such file or directory

Wie stelle ich sicher, dass der erste Befehl an stdoutund der zweite an stderr(hat es funktioniert?) Gedruckt wurde ?


1
Welches Problem versuchen Sie hier zu lösen?
Kenster

3
Hatte Angst, dass jemand danach fragen würde; Keine wirklich, meistens neugierig und in der Hoffnung, mein Verständnis von Umleitung zu verbessern.
KM.

7
Sie können stderredin Ihrer Shell-Umgebung LD_PRELOADzu bekommen stdoutund stderrin verschiedenen Farben. Hier ist eine verwandte Frage in diesem Sinne.
Anko

Antworten:


18

Es ist nicht zu erkennen, ob die Ausgabe bereits gedruckt wurde. In diesem Fall sind beide stdoutund stderrmit dem Terminal verbunden, sodass die Informationen darüber, in welchen Stream geschrieben wurde, bereits verloren waren, als der Text auf Ihrem Terminal angezeigt wurde. Sie wurden vom Programm kombiniert, bevor sie das Terminal erreichten.

In einem Fall wie dem oben beschriebenen können Sie den Befehl mit ausführen stdoutund stderran verschiedene Stellen umleiten, um zu sehen, was passiert. Oder führen Sie es zweimal aus, einmal mit stdoutWeiterleitung zu /dev/nullund einmal mit stderrWeiterleitung zu /dev/null, und überprüfen Sie, in welchem ​​dieser Fälle der Text angezeigt wird.

Sie können zu umleiten stdout, /dev/nullindem Sie >/dev/nullam Ende der Befehlszeile anheften , und Sie können zu umleiten stderr, /dev/nullindem Sie hinzufügen 2>/dev/null.


9

Sie können stdout mit > fileund stderr mit umleiten 2> file. Viele moderne Shells unterstützen die Umleitung zu Befehlen, sodass Sie sedhervorheben können, welche Ausgabe von welchem ​​Stream stammt:

$ ls 2> >(sed 's/^/2: /') > >(sed 's/^/1: /')
1: unity_support_test.0
1: vmwareDnD

$ ls foo 2> >(sed 's/^/2: /') > >(sed 's/^/1: /')
2: ls: cannot access foo: No such file or directory

Sehr schön! Es wäre großartig, wenn man die Linien farblich hervorheben könnte und nicht als Präfix.
Dotancohen

3
@dotancohen: Man kann! ZB(echo "this is stdout"; echo "this is stderr" >&2) > >(sed 's/.*/\x1b[32m&\x1b[0m/') 2> >(sed 's/.*/\x1b[31m&\x1b[0m/')
PM 2Ring

Beachten Sie, dass bei einer gemischten Ausgabe von stdout und stderr zuerst stdout und dann stderr gedruckt wird.
nyuszika7h

5

Mit dem annotate-outputSkript von Debian devscriptskönnen Sie dies selektiv tun:

$ annotate-output ls -ld /test
14:54:22 -: Started ls -ld /test
14:54:22 E: ls: cannot access /test: No such file or directory
14:54:22 -: Finished with exitcode 2

Die zweite Spalte zeigt stdout und stderr mit Ound Ean.

Es gibt einige Vorbehalte, von denen der Haupt wie in den anderen Antworten angegeben ist: Sie können dies nicht nachträglich tun. Weder der Shell noch dem Terminal ist bekannt, wie ein beliebiges Programm seine Dateideskriptoren verwendet, obwohl die Shell für die anfängliche Einrichtung verantwortlich ist.

Bei dieser Methode werden Fifos verwendet. Das Schreiben in ein Fifo kann sich anders verhalten als das Schreiben in ein Tty. Das Schreiben in zwei verschiedene Fifos ist definitiv unterschiedlich (potenzielle Timing- / Interleaving-Probleme). Es ist auch nicht für den interaktiven Gebrauch geeignet, zB annotate-output bashist es kein großartiger Plan, aber für viele andere Zwecke nützlich. Es gibt viele, viele Beispiele für Skripte und Shell-Funktionen, die Antworten auf verwandte Fragen zum Kolorieren von stdin / stdout / stderr geben. Das robusteste ist stderrd, das die Laufzeitmodifikation von (den meisten) Programmen verwendet, um in stderr geschriebene Daten zu ändern.

Diese Frage, auf die Anko verweist, hat gute Antworten zu diesem verwandten Thema: Einfärben der Ausgabe von stdout / stderr: Kann ich meine Shell so konfigurieren, dass STDERR und STDOUT in verschiedenen Farben gedruckt werden?


1
Beachten Sie, dass es sich um ein bashSkript handelt, das while readSchleifen verwendet und einen dateBefehl für jede Zeile von stdout oder stderr ausführt. Daher ist es weitaus weniger effizient als das cmd > >(ts '%T O:') 2> >(ts '%T E:')entsprechende Skript .
Stéphane Chazelas

1

Abgesehen von den anderen Antworten ist es interessant darauf hinzuweisen /proc/$PID/fd(obwohl es die Frage nicht beantwortet):

$ cat > /dev/null 2> /tmp/blablah &
[1] 3073

[1]+  Stopped                 cat > /dev/null 2> /tmp/blablah
$ ls -l /proc/3073/fd
total 0
lrwx------ 1 kampde kampde 64 Feb 24 11:43 0 -> /dev/pts/33
l-wx------ 1 kampde kampde 64 Feb 24 11:43 1 -> /dev/null
l-wx------ 1 kampde kampde 64 Feb 24 11:43 2 -> /tmp/blablah

Wie Sie sehen, sehen Sie hier die Dateideskriptoren, die für einen Prozess geöffnet wurden. 0ist das STDIN, 1ist das STDOUTund 2ist das STDERR. Wenn Sie STDOUT oder STDERR nicht umgeleitet hätten, würden Sie /dev/pts/33(zumindest in diesem Beispiel) sehen, dass sie auf das Terminal verweisen würden.

hinweise : /proc/$PIDexistiert nur für laufende prozesse. In diesem Fall habe ich catohne Argumente verwendet, damit es nicht endet, bis ich das schließe STDIN. Ich habe es auch im Hintergrund ausgeführt, so dass ich die PID für dieses Beispiel sofort habe.


0

Es ist nicht ganz klar, was Sie fragen, aber dies könnte helfen

ls -ld /
echo $?    # Exit status 0 returned because command executed successfully.

ls -ld /test
echo $?    # Non-zero exit status returned -- command failed to execute

Quelle

Wenn der Exit-Code 0 ist, bedeutet dies einfach, dass der Befehl korrekt ausgeführt wird (stdout). Hier finden Sie Bedeutungen, wenn der Exit-Code nicht 0 ist (stderr).


Sehr interessant! Ich hätte niemals Exit-Status mit Umleitung verbunden. Bedeutet Null stdoutund Nicht-Null stderr?
KM.

7
@ KM., Nein. Ich würde sagen, es korreliert stark, aber es gibt nichts, was ein Programm davon abhält, in stderreinen guten Fehlercode zu schreiben stdoutund diesen zurückzugeben , oder in einen schlechten Fehlercode zu schreiben und ihn zurückzugeben. Versuchen find /rootSie in der Tat - vorausgesetzt, Sie sind nicht als root angemeldet -, 2 Zeilen auszudrucken - "/ root" wird gedruckt stdoutund "find: / root: Berechtigung verweigert" wird gedruckt stderr. Und find gibt einen falschen Rückkehrcode zurück.
Godlygeek

Das Problem von op ist klar, wie man erkennt, ob es sich um stdout oder stderr handelt.
it_is_a_literature

0

In der Regel wird STDERR der Nachricht der Programmname mit einem Doppelpunkt vorangestellt.

Beispiel:

rpm -zq some_utils 
rpm: -zq: unknown option

Vs

rpm -ql some_utils 
package some_utils is not installed

-1

So erfassen und testen Sie die Fehlerausgabe:

ls -l test 2>errors
if [ -s errors ]; then echo "There were errors:" && cat errors; fi
rm errors
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.