GNU/Linux >> Linux Esercitazione >  >> Linux

Convogliare solo STDERR attraverso un filtro

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:

  1. Prima salva lo stdout come &3 (&1 viene ingannato in 3)
  2. Successivamente invia stdout a stderr (&2 viene ingannato in 1)
  3. Invia stderr a &3 (stdout) (&3 viene ingannato in 2)
  4. 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

Linux
  1. 6 opzioni di filtro del traffico di rete tcpdump

  2. Fai uscire Tail -f su un tubo rotto?

  3. Come reindirizzare solo Stderr?

  4. Trova l'unica destinazione del collegamento simbolico?

  5. Annulla completamento, ma solo completamento, in Zsh?

Come monitorare l'avanzamento dei dati attraverso un tubo utilizzando il comando "pv".

Reindirizzamento e uscita del tubo?

Come inviare comandi a qualsiasi terminale?

Tubo da B a D? – A&&B || C | D?

Shell:reindirizza stdout a /dev/null e stderr a stdout

Perché il traffico di rete Linux passa solo attraverso eth0?