¿Hay alguna forma, en bash, de canalizar STDERR a través de un filtro antes de unificarlo con STDOUT? Es decir, quiero
STDOUT ────────────────┐
├─────> terminal/file/whatever
STDERR ── [ filter ] ──┘
más bien que
STDOUT ────┐
├────[ filter ]───> terminal/file/whatever
STDERR ────┘

Respuestas:
Aquí hay un ejemplo, modelado a partir de 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 outputCitando el enlace anterior:
fuente
3>&2 2>&1 1>&3-.Un uso ingenuo de la sustitución de procesos parece permitir el filtrado por
stderrseparado destdout::; ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 ) out e:errTenga en cuenta que
stderrsale en la partestderrystdouten lastdoutque podemos ver envolviendo todo el asunto en otro subnivel y redirigir a los archivosoye( ( echo out ; echo err >&2 ) 2> >( sed s/^/e:/ >&2 ) ) 1>o 2>efuente
$como símbolo del sistema. Luego se escriben a menudo ejemplos de concha como:$ cat /var/log/syslog | fgrep .... Sin embargo, esta línea no es copiable debido a la extensión$.:;parece un indicador pero es básicamente un shell no-op; para que pueda seleccionar y pegar toda la línea de forma segura.TL; DR:
Ejemplo:
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, consulte aquí .Explicación
De lejos, la forma más fácil de hacer esto es redirigir STDERR mediante la sustitución de procesos :
Entonces, lo que obtienes con la sustitución de procesos es un nombre de archivo.
Como podrías hacer:
tu puedes hacer
El STDOUT de
>&2la redirecciónfiltervuelve al STDERR original.fuente
exec 2> >(while .. read .. echo)en un script que se ejecuta como un servicio systemd. journald captura fd2 del servicio e infiere el nivel de registro de un prefijo '<N>': anteponer<2>a las líneas de salida, y obtiene el nivel de ERROR asignado a los registros de diario. Pero a veces systemd fue más rápido para matar a todo el grupo de procesos al salir del principal antes de que pudiera registrar su último, ¡el mensaje más importante!TL; DR: (bash y zsh)
Ejemplo:
Muchas respuestas en la red 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}shasignará 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 POSIX no admite descriptores de archivos con nombre
sh.El otro problema con lo anterior es que el comando no se puede canalizar a otros comandos sin volver a intercambiar STDOUT y STDERR a sus valores originales.
Para permitir la tubería en adelante en POSIX
sh, (y aún asumiendo que FD 3 no se usa) se vuelve complicado :Entonces, dada la suposición y la sintaxis retorcida de esto, es probable que sea mejor usar la sintaxis
bash/ más simple que sezshmuestra en el TL; DR anterior y se explica aquí .fuente
Encuentro el uso de la sustitución del proceso bash más fácil de recordar y usar ya que refleja la intención original casi literalmente. Por ejemplo:
$ cat ./p echo stdout echo stderr >&2 $ ./p 2> >(sed -e 's/s/S/') | sed 's/t/T/' sTdout STderrutiliza el primer comando sed como filtro solo en stderr y el segundo comando sed para modificar la salida unida.
Tenga en cuenta que el espacio en blanco después de 2> es obligatorio para que el comando se analice correctamente.
fuente
La última parte de esta página de Advanced Bash Scripting Guide es "redireccionar solo stderr a una tubería".
Esto puede ser lo que quieras. Si no, alguna otra parte de la ABSG debería poder ayudarte, es excelente.
fuente
Eche un vistazo a las tuberías con nombre:
fuente
cat - errromperá la intercalación de stdout y stderr?