Tengo un programa que escribe información en stdout
y stderr
, y necesito hacerlo a 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?
command 2| othercommand
. Bash es tan perfecto que el desarrollo terminó en 1982, así que nunca lo veremos en bash, me temo.Respuestas:
Primero redirige stderr a stdout: la tubería; luego redirija stdout a
/dev/null
(sin cambiar a dónde va stderr):Para obtener detalles sobre la redirección de E / S en toda su variedad, consulte el capítulo sobre redirecciones en el manual de referencia de Bash.
Tenga en cuenta que la secuencia de redireccionamientos de E / S se interpreta de izquierda a derecha, pero las tuberías 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 abiertos. 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 al que stdout se refiere actualmente (verdup2()
yopen()
). La operación>/dev/null
luego cambia el descriptor de archivo 1 para que se refiera a una descripción de archivo abierto/dev/null
, pero eso no cambia el hecho de que el descriptor de archivo 2 se refiere a la descripción de archivo abierto a la que el descriptor de archivo 1 apuntaba originalmente, es decir, la tubería.fuente
command 2> /dev/stdout 1> /dev/null | grep 'something'
/dev/stdout
et al, o usar/dev/fd/N
. Serán marginalmente menos eficientes a menos que el shell los trate como casos especiales; la notación numérica pura no implica acceder a los archivos por nombre, pero el uso de los dispositivos significa una búsqueda de nombre de archivo. Si se puede medir eso es discutible. Me gusta la brevedad de la notación numérica, pero la he estado usando durante tanto tiempo (más de un cuarto de siglo; ¡ay!) Que no estoy calificado para juzgar sus méritos en el mundo moderno.2>&1
, lo que significa 'conectar stderr al descriptor de archivo al que va stdout actualmente '. La segunda operación es 'cambiar stdout para que vaya a/dev/null
', dejando stderr yendo al stdout original, la tubería. El caparazón divide las cosas en el símbolo de la tubería primero, por lo tanto, la redirección de la tubería ocurre antes de las redirecciones2>&1
o>/dev/null
, pero eso es todo; Las otras operaciones son de izquierda a derecha. (De derecha a izquierda no funcionaría)/dev/null
el nombre al equivalente de Windowsnul
).O para intercambiar la salida del error estándar y la salida estándar, use:
Esto crea un nuevo descriptor de archivo (3) y lo asigna al mismo lugar que 1 (salida estándar), luego asigna fd 1 (salida estándar) al mismo lugar que fd 2 (error estándar) y finalmente asigna fd 2 (error estándar ) al mismo lugar que fd 3 (salida estándar).
El error estándar ahora está disponible como salida estándar y la salida estándar anterior se conserva en error estándar. Esto puede ser excesivo, pero esperamos que brinde más detalles sobre los descriptores de archivos Bash (hay nueve disponibles para cada proceso).
fuente
3>&-
cerrar el descriptor de repuesto que creó desde stdoutstderr
y otro que tenga la combinación destderr
ystdout
? En otras palabras, ¿puedenstderr
ir a dos archivos diferentes a la vez?En Bash, también puede redirigir a una subshell utilizando la sustitución de procesos :
Para el caso en cuestión:
fuente
command 2> >(grep 'something' > grep.log)
grep.log contiene el mismo resultado que ungrepped.log decommand 2> ungrepped.log
2> >(stderr pipe >&2)
. De lo contrario, la salida del "tubo stderr" pasará por el "tubo stdlog".2> >(...)
, funciona, lo intenté2>&1 > >(...)
pero no fue asíawk -f /new_lines.awk <in-content.txt > out-content.txt 2> >(tee new_lines.log 1>&2 )
En este caso, también quería ver lo que salía como errores en mi consola. Pero STDOUT iba al archivo de salida. Entonces, dentro del subconjunto, debe redirigir ese STDOUT de nuevo a STDERR dentro de los paréntesis. Mientras eso funciona, la salida STDOUT deltee
comando termina al final delout-content.txt
archivo. Eso me parece inconsistente.2>&1 1> >(dest pipe)
Combinando la mejor de estas respuestas, si lo haces:
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 eliminarlos juntos, ni usar ningún archivo temporal.
fuente
command 2> >(grep -v something)
(sin1>&2
) lo mismo?tar cfz my.tar.gz mydirectory/ 2> >(grep -v 'changed as we read it' 1>&2)
debería funcionar.Es mucho más fácil visualizar las cosas si piensas en lo que realmente está sucediendo con los "redireccionamientos" y las "canalizaciones". Los redireccionamientos y las canalizaciones en bash hacen una cosa: modificar dónde apuntan los descriptores de archivo de proceso 0, 1 y 2 (ver / proc / [pid] / fd / *).
Cuando una tubería o "|" El operador está presente en la línea de comando, lo primero que sucede es que bash crea un fifo y señala 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 redireccionamiento para cada lado se evalúan de izquierda a derecha , y la configuración actual se utiliza cada vez que se produce la duplicación del descriptor. Esto es importante porque, dado que la tubería se configuró primero, el FD1 (lado izquierdo) y el FD0 (lado derecho) ya han cambiado de lo que podrían haber sido normalmente, y cualquier duplicación de estos reflejará ese hecho.
Por lo tanto, cuando escribe algo como lo siguiente:
Esto es lo que sucede, en orden:
Entonces, todos los resultados que el "comando" escribe en su FD 2 (stderr) se dirigen a la tubería y son leídos por "grep" en el otro lado. Todos los resultados que el "comando" escribe en su FD 1 (stdout) llegan a / dev / null.
Si, en cambio, ejecuta lo siguiente:
Esto es lo que pasa:
Entonces, todos los stdout y stderr del "comando" 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 las redirecciones (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.
fuente
Si está usando Bash, entonces use:
http://www.gnu.org/software/bash/manual/bashref.html#Pipelines
fuente
|&
es igual a2>&1
que combina stdout y stderr. La pregunta solicitó explícitamente la salida sin stdout.>/dev/null |&
expanda>/dev/null 2>&1 |
y significa que el inodo stdout está vacío para canalizar porque nadie (# 1 # 2 tanto vinculado a / dev / inodo nulo) está vinculado al inodo stdout (por ejemplols -R /tmp/* >/dev/null 2>&1 | grep i
, dará vacío, perols -R /tmp/* 2>&1 >/dev/null | grep i
dejará # 2 que atado al inodo estándar se canalizará).( echo out; echo err >&2 ) >/dev/null |& grep "."
no da salida (donde queremos "err").man bash
dice If | & se usa ... es la abreviatura de 2> & 1 |. Esta redirección implícita del error estándar a la salida estándar se realiza después de cualquier redirección especificada por el comando. Entonces, primero redirigimos el comando FD1 a nulo, luego redirigimos el comando FD2 a donde FD1 apuntó, es decir. nulo, por lo que grep's FD0 no recibe ninguna entrada. Consulte stackoverflow.com/a/18342079/69663 para obtener una explicación más detallada.Para aquellos que desean redirigir stdout y stderr permanentemente a archivos, grep en stderr, pero mantén el stdout para escribir mensajes en un tty:
fuente
Esto redirigirá command1 stderr a command2 stdin, mientras deja command1 stdout como está.
Tomado de LDP
fuente
Acabo de encontrar una solución para enviar
stdout
a un comando ystderr
a otro, utilizando tuberías con nombre.Aquí va.
Probablemente sea una buena idea eliminar las tuberías con nombre después.
fuente
Puede usar el shell rc .
Primero instale el paquete (es menos de 1 MB).
Este un ejemplo de cómo se deseche la salida estándar y el error estándar de tubo de grep en
rc
:Puedes hacerlo sin salir de Bash:
Como habrá notado, puede especificar qué descriptor de archivo desea canalizar utilizando corchetes después de la canalización.
Los descriptores de archivo estándar están numerados como tales:
fuente
Trato de seguir, encuentro que funciona también,
fuente