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:
- Se crea un tubo (fifo). El "comando FD1" apunta a esta tubería. "grep FD0" también apunta a esta tubería
- "el comando FD2" apunta a donde "comando FD1" apunta actualmente (la tubería)
- "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:
- se crea una canalización y se le señala "comando FD 1" y "grep FD 0"
- "el comando FD 1" apunta a / dev / null
- "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''