GNU/Linux >> Tutoriels Linux >  >> Linux

Canaliser uniquement STDERR à travers un filtre

TL ;DR :

$ cmd 2> >(stderr-filter >&2)

Exemple :

% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%

Cela fonctionnera à la fois dans bash et zsh. Bash est à peu près omniprésent de nos jours, cependant, si vous avez vraiment besoin d'une solution (vraiment noueuse) pour POSIX sh , alors voir ici.

Explication

De loin, le moyen le plus simple de procéder consiste à rediriger STDERR via la substitution de processus :

La substitution de processus permet de faire référence à l'entrée ou à la sortie d'un processus à l'aide d'un nom de fichier. Il prend la forme de

>(list)

La liste de processus est exécutée de manière asynchrone et son entrée ou sa sortie apparaît sous la forme d'un nom de fichier.

Ainsi, ce que vous obtenez avec la substitution de processus est un nom de fichier.

Comme vous pourriez le faire :

$ cmd 2> filename

vous pouvez faire

$ cmd 2> >(filter >&2)

Le >&2 le filter de la redirection STDOUT de revient au STDERR d'origine.


TL;DR :(bash et zsh)

$ cmd 2> >(stderr-filter >&2)

Exemple :

% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%

De nombreuses réponses sur le réseau StackExchange ont la forme :

cat /non-existant 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g'

Cela a une hypothèse intégrée :que le descripteur de fichier 3 n'est pas utilisé pour autre chose.

Utilisez plutôt un descripteur de fichier nommé et {ba,z}sh allouera le prochain descripteur de fichier disponible>=10 :

cat /non-existant {tmp}>&1 1>&2 2>&$tmp {tmp}>&- | sed 's/e/E/g'

Notez que les descripteurs de fichiers nommés ne sont pas pris en charge par POSIX sh .

L'autre problème avec ce qui précède est que la commande ne peut pas être redirigée vers d'autres commandes sans remplacer à nouveau STDOUT et STDERR par leurs valeurs d'origine.

Pour autoriser la canalisation vers l'avant dans POSIX sh , (et toujours en supposant que FD 3 ne l'utilise pas) ça se complique :

(cmd 2>&1 >&3 3>&- | stderr-filter >&2 3>&-) 3>&1

Donc, étant donné l'hypothèse et la syntaxe noueuse de ceci, vous feriez probablement mieux d'utiliser le plus simple bash /zsh syntaxe montrée dans le TL;DR ci-dessus, et expliquée ici.

démonstration pratique, grepping uniquement 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

Voici un exemple, inspiré de la façon d'échanger des descripteurs de fichiers dans bash . La sortie de a.out est la suivante, sans le préfixe '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

Citation du lien ci-dessus :

  1. Enregistrez d'abord stdout en tant que &3 (&1 est dupliqué en 3)
  2. Envoyer ensuite stdout à stderr (&2 est dupé en 1)
  3. Envoie stderr à &3 (stdout) (&3 est dupé en 2)
  4. fermer &3 (&- est dupé en 3)

Une utilisation naïve de la substitution de processus semble permettre le filtrage de stderr séparément de stdout :

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

Notez que stderr sort le stderr et stdout le stdout , que nous pouvons voir en enveloppant le tout dans un autre sous-shell et en redirigeant vers les fichiers o et e

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

Linux
  1. Filtre Rsync :copie d'un seul motif ?

  2. Faire sortir Tail -f sur un tuyau cassé ?

  3. Comment rediriger uniquement Stderr ?

  4. Comment diriger les commandes vers n'importe quel terminal ?

  5. Comment filtrer le journal Dmesg pour ne voir que les erreurs ?

Comment surveiller la progression des données dans un tube à l'aide de la commande "pv"

Rediriger et canaliser la sortie ?

Trouver uniquement la destination du lien symbolique ?

Annuler l'achèvement, mais uniquement l'achèvement, dans Zsh ?

Tuyau B à D ? – A &&B || C | RÉ?

Pourquoi le trafic réseau Linux ne passe-t-il que par eth0 ?