TL;DR:
$ cmd 2> >(stderr-filter >&2)
Beispiel:
% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%
Dies funktioniert sowohl in bash als auch in zsh. Bash ist heutzutage jedoch ziemlich allgegenwärtig, wenn Sie wirklich eine (wirklich knorrige) Lösung für POSIX sh
benötigen , dann siehe hier.
Erklärung
Der bei weitem einfachste Weg, dies zu tun, besteht darin, STDERR über die Prozesssubstitution umzuleiten:
Die Prozesssubstitution ermöglicht es, auf die Eingabe oder Ausgabe eines Prozesses unter Verwendung eines Dateinamens zu verweisen. Es hat die Form
>(list)
Die Prozessliste wird asynchron ausgeführt und ihre Eingabe oder Ausgabe erscheint als Dateiname.
Was Sie also mit der Prozesssubstitution erhalten, ist ein Dateiname.
So wie Sie es tun könnten:
$ cmd 2> filename
du kannst
$ cmd 2> >(filter >&2)
Die >&2
filter
umleiten 's STDOUT zurück auf die ursprüngliche STDERR.
TL;DR:(bash und zsh)
$ cmd 2> >(stderr-filter >&2)
Beispiel:
% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%
Viele Antworten im StackExchange-Netzwerk haben die Form:
cat /non-existant 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g'
Dies hat eine eingebaute Annahme:dass Dateideskriptor 3 nicht für etwas anderes verwendet wird.
Verwenden Sie stattdessen einen benannten Dateideskriptor und {ba,z}sh
weist den nächsten verfügbaren Dateideskriptor>=10:
cat /non-existant {tmp}>&1 1>&2 2>&$tmp {tmp}>&- | sed 's/e/E/g'
Beachten Sie, dass benannte Dateideskriptoren von POSIX sh
nicht unterstützt werden .
Das andere Problem mit dem oben Gesagten ist, dass der Befehl nicht an weitere Befehle weitergeleitet werden kann, ohne STDOUT und STDERR wieder auf ihre ursprünglichen Werte zurückzusetzen.
Um die Weiterleitung in POSIX sh
zu ermöglichen , (und immer noch davon aus, dass FD 3 nicht verwendet wird) wird es kompliziert:
(cmd 2>&1 >&3 3>&- | stderr-filter >&2 3>&-) 3>&1
Angesichts der Annahme und der knorrigen Syntax davon sind Sie wahrscheinlich besser dran, wenn Sie den einfacheren bash
verwenden /zsh
Syntax, die oben im TL;DR gezeigt und hier erklärt wird.
praktische Demonstration, gruppiert nur stderr:
$ ls -l . noexistABC noexistXYZ
ls: cannot access 'noexistABC': No such file or directory
ls: cannot access 'noexistXYZ': No such file or directory
.:
total 4
-rw-rw-r-- 1 frank frank 0 Aug 19 12:26 bar.txt
-rw-rw-r-- 1 frank frank 0 Aug 19 12:26 foo.txt
drwxrwxr-x 2 frank frank 4096 Aug 19 12:26 someFolder
$ ( ls -l . noexistABC noexistXYZ 2>&1 >&3 3>&- | grep ABC >&2 3>&-) 3>&1
.:
ls: cannot access 'noexistABC': No such file or directory
total 4
-rw-rw-r-- 1 frank frank 0 Aug 19 12:26 bar.txt
-rw-rw-r-- 1 frank frank 0 Aug 19 12:26 foo.txt
drwxrwxr-x 2 frank frank 4096 Aug 19 12:26 someFolder
Hier ist ein Beispiel, das dem Austausch von Dateideskriptoren in bash nachempfunden ist. 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
Zitat aus obigem Link:
- Speichern Sie zuerst stdout als &3 (&1 wird in 3 dupliziert)
- Sende als nächstes stdout an stderr (&2 wird in 1 dupliziert)
- Sende stderr an &3 (stdout) (&3 wird in 2 dupliziert)
- &3 schließen (&- wird in 3 überführt)
Eine naive Verwendung der Prozesssubstitution scheint das Filtern von stderr
zu ermöglichen getrennt von stdout
:
:; ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 )
out
e:err
Beachten Sie, dass stderr
erscheint auf stderr
und stdout
auf stdout
, was wir sehen können, indem wir das Ganze in eine andere Subshell packen und auf die Dateien o
umleiten und e
( ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 ) ) 1>o 2>e