TL;DR:
$ cmd 2> >(stderr-filter >&2)
Ejemplo:
% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%
Esto funcionará tanto en bash como en zsh. Bash es bastante omnipresente en estos días, sin embargo, si realmente necesita una solución (realmente retorcida) para POSIX sh , entonces mira aquí.
Explicación
De lejos, la forma más fácil de hacer esto es redirigir STDERR a través de la sustitución de procesos:
La sustitución de procesos permite hacer referencia a la entrada o salida de un proceso mediante un nombre de archivo. Toma la forma de
>(list)
La lista de procesos se ejecuta de forma asíncrona y su entrada o salida aparece como un nombre de archivo.
Entonces, lo que obtienes con la sustitución de procesos es un nombre de archivo.
Al igual que podrías hacer:
$ cmd 2> filename
puedes hacer
$ cmd 2> >(filter >&2)
El >&2 filter de redirección STDOUT de nuevo al STDERR original.
TL; DR:(bash y zsh)
$ cmd 2> >(stderr-filter >&2)
Ejemplo:
% cat /non-existant 2> >(tr o X >&2)
cat: /nXn-existant: NX such file Xr directXry
%
Muchas respuestas en la red de StackExchange tienen la forma:
cat /non-existant 3>&1 1>&2 2>&3 3>&- | sed 's/e/E/g'
Esto tiene una suposición incorporada:que el descriptor de archivo 3 no se usa para otra cosa.
En su lugar, utilice un descriptor de archivo con nombre y {ba,z}sh asignará el siguiente descriptor de archivo disponible>=10:
cat /non-existant {tmp}>&1 1>&2 2>&$tmp {tmp}>&- | sed 's/e/E/g'
Tenga en cuenta que los descriptores de archivos con nombre no son compatibles con POSIX sh .
El otro problema con lo anterior es que el comando no se puede canalizar a más comandos sin volver a cambiar STDOUT y STDERR a sus valores originales.
Para permitir la canalización hacia adelante en POSIX sh , (y aún suponiendo que FD 3 no se use) se complica:
(cmd 2>&1 >&3 3>&- | stderr-filter >&2 3>&-) 3>&1
Entonces, dada la suposición y la sintaxis retorcida de esto, es probable que sea mejor usar el bash más simple /zsh sintaxis que se muestra en el TL;DR anterior y se explica aquí.
demostración práctica, 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
Aquí hay un ejemplo, inspirado en cómo intercambiar descriptores de archivos en bash. La salida de a.out es la siguiente, sin el prefijo '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 del enlace anterior:
- Primero guarde la salida estándar como &3 (&1 se convierte en 3)
- A continuación, envíe stdout a stderr (&2 se convierte en 1)
- Enviar stderr a &3 (stdout) (&3 se convierte en 2)
- cerrar &3 (&- se convierte en 3)
Un uso ingenuo de la sustitución de procesos parece permitir el filtrado de stderr por separado de stdout :
:; ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 )
out
e:err
Tenga en cuenta que stderr sale en stderr y stdout en stdout , que podemos ver envolviendo todo en otra subcapa y redirigiendo a los archivos o y e
( ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 ) ) 1>o 2>e