2010-09-01 8 views
41

Gibt es eine Möglichkeit, stderr in bash, durch einen Filter pipe vor Vereinheitlichung mit stdout? Das heißt, ichPipe nur Stderr durch einen Filter

wollen
stdout ----------------\ 
         |-----> terminal/file/whatever 
stderr -- [ filter ] --/ 

statt

stdout ----\ 
      |----[ filter ]---> terminal/file/whatever 
stderr ----/ 
+1

Siehe auch [Wie Rohr stderr und nicht stdou t?] (http://stackoverflow.com/questions/2342826/how-to-pipe-stderr-and-not-stdout). –

Antwort

43

Hier ist ein Beispiel, nach how to swap file descriptors in bash modelliert. Die Ausgabe von a.out ist die folgende ohne das Präfix "STDXXX:".

STDERR: stderr output 
STDOUT: more regular 

./a.out 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g' 
more regular 
stdErr output 

aus dem obigen Link Zitiert:

  1. Erste stdout speichern als & 3 (& 1 in 3 getäuscht wird)
  2. Weiter stdout Stderr senden (& 2 düpiert in 1)
  3. Senden stderr zu & 3 (stdout) (& 3 ist in 2)
  4. schließen & 3 (& - ist in 3 übertölpelt)
+1

Zusätzliche Referenz: [BashFAQ/047] (http://mywiki.wooledge.org/BashFAQ/047) –

+4

Dies funktioniert mit jeder POSIX-Shell, nicht nur Bash. – Rufflewind

+0

Es funktioniert nicht für mich. Schließlich mache ich es mit '3> & 2 2> & 1 1> & 3-' arbeiten. – aleung

5

Der letzte Teil der this page des Advanced Bash Scripting Guide ist "nur stderr zu einem Rohr umgeleitet".

# Nur stderr an eine Pipe umleiten.

exec 3>&1        # Save current "value" of stdout. 
ls -l 2>&1 >&3 3>&- | grep bad 3>&- # Close fd 3 for 'grep' (but not 'ls'). 
#    ^^^^ ^^^^ 
exec 3>&-        # Now close it for the remainder of the script. 

# Danke, S. C.

Dies kann sein, was Sie wollen. Wenn nicht, sollte ein anderer Teil des ABSG Ihnen helfen können, es ist ausgezeichnet.

+0

Wir sind etwas zögerlich, das ABSG als Referenz zu empfehlen, da es Dokumentation, Verordnung und Meinung mischt, ohne die Unterschiede klar zu kennzeichnen. Einige Abschnitte haben auch zweifelhaften Inhalt, obwohl der eine Link scheint gut zu sein. – tripleee

3

einen Blick auf Named Pipes Nehmen:

$ mkfifo err 
$ cmd1 2>err |cat - err |cmd2 
+0

wird "cat - err" nicht das durchsetzen von stdout und stderr unterbrechen? –

+0

@Martin - es kommt darauf an. Wenn die Cmd1-, Cat-, ** oder ** Cmd2-Puffer ausgegeben werden, könnten Sie die Ausgabe außerhalb der Reihenfolge sehen. – mob

7

Ich finde die Verwendung von bash Prozess Substitution leichter merken und zu verwenden, da es fast wörtlich die ursprüngliche Absicht widerspiegelt. Zum Beispiel:

$ cat ./p 
echo stdout 
echo stderr >&2 
$ ./p 2> >(sed -e 's/s/S/') | sed 's/t/T/' 
sTdout 
STderr 

verwendet den ersten Sed Befehl als ein Filter auf Stderr nur und dem zweiten Befehl, um die SED verbundenen Ausgang zu modifizieren.

Beachten Sie, dass der Leerraum nach 2> obligatorisch ist, damit der Befehl korrekt analysiert wird.

14

Eine naive Verwendung von Prozess Substitution scheint von stdout Filterung von stderr separat zu ermöglichen:

:; (echo out ; echo err >&2) 2> >(sed s/^/e:/ >&2) 
out 
e:err 

Beachten Sie, dass stderr kommt auf stderr und stdout auf stdout, die wir durch das Einwickeln das Ganze in einem anderen sehen können Subshell und Umleitung auf Dateien o und e

((echo out ; echo err >&2) 2> >(sed s/^/e:/ >&2)) 1>o 2>e 
+0

warum das:; am Anfang? Ich habe die magische Linie ohne versucht und scheint keinen Unterschied zu machen. – Koshmaar

+0

Einige Leute verwenden '$' als Eingabeaufforderung. Dann schreiben sie oft Shell-Beispiele wie: '$ cat/var/log/syslog | fgrep ... '. Diese Zeile ist jedoch wegen des '$' nicht kopierfähig. ':;' sieht aus wie eine Eingabeaufforderung, ist aber im Grunde ein Shell-No-Op; So können Sie die gesamte Linie auswählen und einfügen. – solidsnack

+11

Ok, aber Sie könnten einfach weglassen:; und die Zeile wäre auch copy-pastable :) Für mich:; sieht nicht wie eine Eingabeaufforderung aus, es hat das Beispiel nicht klarer gemacht (Befehle von Ausgabe trennen), aber verwirrend. Obwohl ich Ihre Sichtweise verstehe und über Syntax/Konventionen nicht nachdenke. – Koshmaar