TL;DR:
$ cmd 2> >(stderr-filter >&2)
Esempio:
% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%
Funzionerà sia in bash che in zsh. Bash è praticamente onnipresente in questi giorni, tuttavia, se hai davvero bisogno di una soluzione (davvero nodosa) per POSIX sh
, quindi vedi qui.
Spiegazione
Di gran lunga, il modo più semplice per farlo è reindirizzare STDERR tramite la sostituzione del processo:
La sostituzione del processo consente di fare riferimento all'input o all'output di un processo utilizzando un nome file. Ha la forma di
>(list)
L'elenco dei processi viene eseguito in modo asincrono e il suo input o output viene visualizzato come nome file.
Quindi quello che ottieni con la sostituzione del processo è un nome file.
Proprio come potresti fare tu:
$ cmd 2> filename
puoi farlo
$ cmd 2> >(filter >&2)
Il >&2
filter
del reindirizzamento 's STDOUT torna allo STDERR originale.
TL;DR:(bash e zsh)
$ cmd 2> >(stderr-filter >&2)
Esempio:
% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%
Molte risposte sulla rete StackExchange hanno la forma:
cat /non-existant 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g'
Questo ha un presupposto incorporato:quel descrittore di file 3 non viene utilizzato per qualcos'altro.
Usa invece un descrittore di file con nome e {ba,z}sh
allocherà il successivo descrittore di file disponibile>=10:
cat /non-existant {tmp}>&1 1>&2 2>&$tmp {tmp}>&- | sed 's/e/E/g'
Nota che i descrittori di file con nome non sono supportati da POSIX sh
.
L'altro problema con quanto sopra è che il comando non può essere reindirizzato ad altri comandi senza riportare STDOUT e STDERR ai loro valori originali.
Per consentire il piping in avanti in POSIX sh
, (e sempre supponendo che FD 3 non lo usi) diventa complicato:
(cmd 2>&1 >&3 3>&- | stderr-filter >&2 3>&-) 3>&1
Quindi, dato il presupposto e la sintassi nodosa di questo, è probabile che tu stia meglio usando il più semplice bash
/zsh
sintassi mostrata nel TL;DR sopra, e spiegata qui.
dimostrazione pratica, grepping solo 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
Ecco un esempio, modellato su come scambiare descrittori di file in bash . L'output di a.out è il seguente, senza il prefisso '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
Citando dal link sopra:
- Prima salva lo stdout come &3 (&1 viene ingannato in 3)
- Successivamente invia stdout a stderr (&2 viene ingannato in 1)
- Invia stderr a &3 (stdout) (&3 viene ingannato in 2)
- chiudi &3 (&- viene ingannato in 3)
Un uso ingenuo della sostituzione del processo sembra consentire il filtraggio di stderr
separatamente da stdout
:
:; ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 )
out
e:err
Nota che stderr
esce su stderr
e stdout
su stdout
, che possiamo vedere avvolgendo il tutto in un'altra subshell e reindirizzando ai file o
e e
( ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 ) ) 1>o 2>e