Frage Wie studerst du stderr, und nicht stdout?


Ich habe ein Programm, das Informationen schreibt stdout und stderrund ich muss grep durch was kommt stderr, während sie ignoriert stdout.

Ich kann es natürlich in 2 Schritten tun:

command > /dev/null 2> temp.file
grep 'something' temp.file

aber ich wäre lieber in der Lage, dies ohne temporäre Dateien zu tun. Gibt es irgendwelche cleveren Tricks?


760
2018-02-26 15:53


Ursprung


Antworten:


Zuerst Redirect Stderr zu stdout - das Rohr; dann umleiten stdout zu /dev/null (ohne zu ändern, wohin stderr geht):

command 2>&1 >/dev/null | grep 'something'

Einzelheiten zur E / A-Umleitung in ihrer ganzen Vielfalt finden Sie im Kapitel über Umleitungen im Bash Referenzhandbuch.

Beachten Sie, dass die Reihenfolge der E / A-Umleitungen von links nach rechts interpretiert wird, aber die Pipes erst eingerichtet werden, bevor die E / A-Umleitungen interpretiert werden. Dateideskriptoren wie 1 und 2 sind Verweise auf geöffnete Dateibeschreibungen. Die Operation 2>&1 Der Dateideskriptor 2 aka stderr verweist auf die gleiche Dateibeschreibung wie der Dateideskriptor 1, auf den sich aka stdout gerade bezieht (siehe dup2() und open()). Die Operation >/dev/null ändert dann den Dateideskriptor 1 so, dass er sich auf eine geöffnete Dateibeschreibung für bezieht /dev/null, aber das ändert nichts an der Tatsache, dass der Dateideskriptor 2 auf die Beschreibung der geöffneten Datei verweist, auf die der Dateideskriptor 1 ursprünglich hinwies - nämlich die Pipe.


902
2018-02-26 15:55



Oder um die Ausgabe von stderr und stdout über die Verwendung zu tauschen: -

command 3>&1 1>&2 2>&3

Dies erzeugt einen neuen Dateideskriptor (3) und weist ihn der gleichen Stelle wie 1 (stdout) zu, weist dann fd 1 (stdout) der gleichen Stelle wie fd 2 (stderr) zu und weist fd 2 (stderr) denselben zu Platziere als fd 3 (stdout). Stderr steht jetzt als stdout und altes stdout in stderr zur Verfügung. Dies ist vielleicht ein Overkill, gibt aber hoffentlich mehr Details zu Bash-Datei-Deskriptoren (es gibt 9 für jeden Prozess).


311
2018-03-04 18:18



In Bash können Sie auch mit einer Subshell umleiten Prozesssubstitution:

command > >(stdlog pipe)  2> >(stderr pipe)

Für den vorliegenden Fall:

command 2> >(grep 'something') >/dev/null

172
2018-02-09 19:14



Kombinieren Sie die besten dieser Antworten, wenn Sie Folgendes tun:

command 2> >(grep -v something 1>&2)

... dann bleiben alle stdout als stdout erhalten und Alles stderr wird als stderr beibehalten, aber Sie werden keine Zeilen in stderr sehen, die mit der Zeichenfolge "something" beginnen.

Dies hat den einzigartigen Vorteil, dass stout und stderr nicht rückgängig gemacht oder verworfen werden, sie nicht zusammengeschmolzen werden oder keine temporären Dateien verwendet werden.


138
2018-04-10 21:05



Es ist viel einfacher, Dinge zu visualisieren, wenn man darüber nachdenkt, was wirklich mit "Redirects" und "Pipes" vor sich geht. Umleitungen und Pipes in bash machen eine Sache: modifizieren, wo die Prozessdateideskriptoren 0, 1 und 2 zeigen (siehe / proc / [pid] / fd / *).

Wenn ein Rohr oder "|" Der Operator ist in der Befehlszeile vorhanden. Das erste, was passiert, ist, dass bash einen FIFO erzeugt und das FD 1 des linken Kommandos auf diesen FIFO zeigt und das FD 0 des rechten Kommandos auf den gleichen FIFO zeigt.

Als Nächstes werden die Umleitungsoperatoren für jede Seite ausgewertet von links nach rechtsund die aktuellen Einstellungen werden immer dann verwendet, wenn der Deskriptor dupliziert wird. Dies ist wichtig, da, da das Rohr zuerst aufgebaut wurde, FD1 (linke Seite) und FD0 (rechte Seite) bereits von dem abweichen, was sie normalerweise gewesen wären, und jede Duplizierung dieser Tatsache spiegelt diese Tatsache wider.

Daher, wenn Sie etwas wie folgt eingeben:

command 2>&1 >/dev/null | grep 'something'

Folgendes geschieht in der Reihenfolge:

  1. Eine Pipe (Fifo) wird erstellt. "command FD1" zeigt auf diese Leitung. "grep FD0" wird auch auf dieses Rohr hingewiesen
  2. "command FD2" zeigt auf wo aktuell "command FD1" zeigt (die Pipe)
  3. "Befehl FD1" wird auf / dev / null gezeigt

Alle Ausgaben, die "command" in ihr FD 2 schreibt (stderr), kommen also auf die Pipe und werden von "grep" auf der anderen Seite gelesen. Alle Ausgaben, die "command" in ihre FD 1 (stdout) schreibt, gehen nach / dev / null.

Wenn Sie stattdessen Folgendes ausführen:

command >/dev/null 2>&1 | grep 'something'

Folgendes passiert:

  1. Eine Pipe wird erstellt und "command FD 1" und "grep FD 0" werden darauf gezeigt
  2. "command FD 1" wird auf / dev / null gezeigt
  3. "command FD 2" zeigt auf wo aktuell FD 1 zeigt (/ dev / null)

Also gehen alle stdout und stderr von "command" zu / dev / null. Nichts geht an die Pipe und somit wird "grep" geschlossen, ohne etwas auf dem Bildschirm anzuzeigen.

Beachten Sie außerdem, dass Redirects (Dateideskriptoren) schreibgeschützt (<), schreibgeschützt (>) oder schreibgeschützt (<>) sein können.

Eine letzte Anmerkung. Ob ein Programm etwas auf FD1 oder FD2 schreibt, liegt allein beim Programmierer. Gute Programmierpraxis schreibt vor, dass Fehlermeldungen zu FD 2 und normaler Ausgabe zu FD 1 gehen sollten, aber Sie werden oft schlampige Programmierung finden, die die beiden vermischt oder die Konvention ignoriert.


82
2017-08-20 18:09



Benutzt du Bash? Wenn ja:

command >/dev/null |& grep "something"

http://www.gnu.org/software/bash/manual/bashref.html#Pipelines


28
2018-04-18 21:56



Für diejenigen, die stdout und stderr dauerhaft in Dateien umleiten möchten, grep auf stderr, aber behalten Sie das stdout, um Nachrichten zu einem tty zu schreiben:

# save tty-stdout to fd 3
exec 3>&1
# switch stdout and stderr, grep (-v) stderr for nasty messages and append to files
exec 2> >(grep -v "nasty_msg" >> std.err) >> std.out
# goes to the std.out
echo "my first message" >&1
# goes to the std.err
echo "a error message" >&2
# goes nowhere
echo "this nasty_msg won't appear anywhere" >&2
# goes to the tty
echo "a message on the terminal" >&3

9
2017-11-14 08:59