operator bash grep stdout pipe stderr

bash - operator - 2>&1



¿Cómo canalizar stderr, y no stdout? (10)

¿Estás usando bash? Si es así:

command >/dev/null |& grep "something"

http://www.gnu.org/software/bash/manual/bashref.html#Pipelines

Tengo un programa que escribe información en stdout y stderr , y necesito grep través de lo que viene a stderr , sin tener en cuenta stdout .

Por supuesto que puedo hacerlo en 2 pasos:

command > /dev/null 2> temp.file grep ''something'' temp.file

pero preferiría poder hacer esto sin archivos temporales. ¿Hay algún truco de tubería inteligente?


Acabo de encontrar una solución para enviar stdout a un comando y stderr a otro, usando canalizaciones con nombre.

Aquí va.

mkfifo stdout-target mkfifo stderr-target cat < stdout-target | command-for-stdout & cat < stderr-target | command-for-stderr & main-command 1>stdout-target 2>stderr-target

Probablemente sea una buena idea quitar las tuberías nombradas después.


Combinando la mejor de estas respuestas, si lo hace:

command 2> >(grep -v something 1>&2)

... entonces todo stdout se conserva como stdout y todo stderr se conserva como stderr, pero no verá ninguna línea en stderr que contenga la cadena "algo".

Esto tiene la ventaja única de no revertir o descartar stdout y stderr, ni mezclarlos juntos, ni usar ningún archivo temporal.


En Bash, también puede redirigir a una subshell usando la sustitución de procesos :

command > >(stdlog pipe) 2> >(stderr pipe)

Para el caso que nos ocupa:

command 2> >(grep ''something'') >/dev/null


Es mucho más fácil visualizar las cosas si piensas en lo que realmente está pasando con "redirecciones" y "tuberías". Los redireccionamientos y canalizaciones en bash hacen una cosa: modifique hacia dónde apuntan los descriptores de archivo de proceso 0, 1 y 2 (consulte / proc / [pid] / fd / *).

Cuando una pipa o "|" el operador está presente en la línea de comando, lo primero que sucede es que bash crea un fifo y apunta el FD 1 del comando del lado izquierdo a este fifo, y apunta el FD 0 del comando del lado derecho al mismo fifo.

A continuación, los operadores de redirección para cada lado se evalúan de izquierda a derecha , y la configuración actual se usa siempre que se produce la duplicación del descriptor. Esto es importante porque desde que se configuró la tubería primero, el FD1 (lado izquierdo) y FD0 (lado derecho) ya se han cambiado de lo que normalmente podrían haber sido, y cualquier duplicación de estos reflejará ese hecho.

Por lo tanto, cuando escribes algo como lo siguiente:

command 2>&1 >/dev/null | grep ''something''

Esto es lo que sucede, en orden:

  1. Se crea un tubo (fifo). El "comando FD1" apunta a esta tubería. "grep FD0" también apunta a esta tubería
  2. "el comando FD2" apunta a donde "comando FD1" apunta actualmente (la tubería)
  3. "el comando FD1" apunta a / dev / null

Por lo tanto, toda la salida que "comando" escribe en su FD 2 (stderr) se abre paso a la tubería y se lee con "grep" en el otro lado. Toda la salida que "comando" escribe en su FD 1 (stdout) se abre paso a / dev / null.

Si por el contrario, ejecuta lo siguiente:

command >/dev/null 2>&1 | grep ''something''

Esto es lo que sucede:

  1. se crea una canalización y se le señala "comando FD 1" y "grep FD 0"
  2. "el comando FD 1" apunta a / dev / null
  3. "el comando FD 2" apunta a donde apunta actualmente FD 1 (/ dev / null)

Entonces, todos los stdout y stderr de "command" van a / dev / null. Nada va a la tubería, y por lo tanto "grep" se cerrará sin mostrar nada en la pantalla.

También tenga en cuenta que los redireccionamientos (descriptores de archivo) pueden ser de solo lectura (<), de solo escritura (>), o de lectura-escritura (<>).

Una nota final. Si un programa escribe algo en FD1 o FD2, depende completamente del programador. La buena práctica de programación dicta que los mensajes de error deben ir a FD 2 y la salida normal a FD 1, pero a menudo encontrará una programación descuidada que mezcla los dos o ignora la convención.


Esto redirigirá command1 stderr a command2 stdin, mientras se deja command1 stdout como está.

exec 3>&1 command1 2>&1 >&3 3>&- | command2 3>&- exec 3>&-

Tomado de LDP


O para cambiar la salida de stderr y stdout sobre el uso: -

command 3>&1 1>&2 2>&3

Esto crea un nuevo descriptor de archivo (3) y lo asigna al mismo lugar que 1 (stdout), luego asigna fd 1 (stdout) al mismo lugar que fd 2 (stderr) y finalmente asigna fd 2 (stderr) al mismo colocar como fd 3 (stdout). Stderr ahora está disponible como stdout y stdout antiguo conservado en stderr. Esto puede ser excesivo, pero se espera que proporcione más detalles sobre los descriptores de archivos bash (hay 9 disponibles para cada proceso).


Para aquellos que quieren redirigir stdout y stderr permanentemente a archivos, grep en stderr, pero mantenga la stdout para escribir mensajes a un tty:

# save tty-stdout to fd 3 exec 3>&1 # switch stdout and stderr, grep (-v) stderr for nasty messages and append to files exec 2> >(grep -v "nasty_msg" >> std.err) >> std.out # goes to the std.out echo "my first message" >&1 # goes to the std.err echo "a error message" >&2 # goes nowhere echo "this nasty_msg won''t appear anywhere" >&2 # goes to the tty echo "a message on the terminal" >&3


Primero redirigir stderr a stdout - la tubería; luego redirigir stdout a /dev/null (sin cambiar a donde va stderr):

command 2>&1 >/dev/null | grep ''something''

Para obtener detalles sobre la redirección de E / S en toda su variedad, consulte el capítulo sobre Redirections en el manual de referencia de Bash.

Tenga en cuenta que la secuencia de redirecciones de E / S se interpreta de izquierda a derecha, pero los conductos se configuran antes de que se interpreten las redirecciones de E / S. Los descriptores de archivos como 1 y 2 son referencias a descripciones de archivos abiertas. La operación 2>&1 hace que el descriptor de archivo 2, también conocido como stderr, se refiera a la misma descripción de archivo abierto que el descriptor de archivo 1, lo que también se conoce como stdout (ver dup2() y open() ). La operación >/dev/null luego cambia el descriptor de archivo 1 para que se refiera a una descripción de archivo abierta para /dev/null , pero eso no cambia el hecho de que el descriptor de archivo 2 se refiere a la descripción de archivo abierto que descriptor de archivo 1 era originalmente apuntando a - a saber, el tubo.


Trato de seguir, encuentro que funciona también,

command > /dev/null 2>&1 | grep ''something''