standard and bash redirect stdout

bash - and - ¿Cómo puedo redireccionar STDERR a STDOUT, pero ignorar el STDOUT original?



pipe bash (3)

Esta pregunta ya tiene una respuesta aquí:

Tengo un programa cuya salida STDERR quiero inspeccionar y ejecutar grep etc.

Así que podría redirigirlo a STDOUT y usar grep, pero el problema es que no quiero el contenido original de STDOUT .

Entonces, este no hará

cmd 2>&1 | grep pattern

porque mezclará STDOUT y STDERR originales.

Y este no funciona, ya que grep no lee la salida STDERR:

cmd 1>/dev/null | grep pattern

Pero también, este no funcionará:

cmd 1>/dev/null 2>&1 | grep pattern

porque la salida estará completamente vacía, ya que todo se escribe en /dev/null .

Pero debe haber una manera simple de hacerlo?


Qué no funciona:

La razón del último comando que citó:

cmd 1>/dev/null 2>&1 | grep pattern

no funciona, surge de una confusión en el orden en que funciona la redirección. Esperaba que la última redirección entrecomillada se aplicara a las anteriores en cada salida, de modo que la salida del descriptor de archivo de salida estándar original (1) irá a / dev / null, y la salida al descriptor de archivo de error estándar (2) ir a la salida estándar original.

Sin embargo, así no es como funciona la redirección de shell. Cada redirección hace que los descriptores de archivo sean "reasignados" cerrando la "fuente" y duplicando el "destino" en ella (vea las páginas man de dup(2) y close(2) ), en orden. Esto significa que en su comando la salida estándar se reemplaza primero con /dev/null , y luego se reemplaza el error estándar con la salida estándar, que ya es /dev/null .

Que funciona:

Por lo tanto, para obtener el efecto deseado, solo necesita invertir las redirecciones. Entonces tendrá error estándar ir a la salida estándar, y la salida estándar original irá a /dev/null :

cmd 2>&1 >/dev/null | grep pattern

(tenga en cuenta que el 1 antes > es necesario - para la salida estándar de salida de redirección es el predeterminado)

Adición : Charlie mencionó la redirección a &- para cerrar un descriptor de archivo. Si usa un shell interactivo que admita esa extensión ( bash y algunas otras implementaciones lo hacen pero no todas y no es estándar ), también puede hacerlo así:

cmd 2>&1 >&- | grep pattern

Esto puede ser mejor; puede ahorrar algo de tiempo, porque cuando el comando intenta escribir en salida estándar, la llamada a write puede fallar inmediatamente sin esperar un cambio de contexto en el kernel y el controlador manejando /dev/null (dependiendo del sistema) implementación de llamada: algunos pueden detectar esto en la función libc , y algunos también pueden tener un manejo especial para /dev/null ). Si hay muchos resultados que pueden valer la pena, y es más rápido escribir.

Esto funcionará principalmente porque a la mayoría de los programas no les importa si no escriben en la salida estándar (¿quién realmente verifica el valor de retorno de printf ?) Y no les importará que la salida estándar esté cerrada. Sin embargo, algunos programas pueden rescatar con un código de falla si la write falla, por lo general bloquean procesadores, programas que utilizan una biblioteca cuidadosa para E / S o que inician sesión en la salida estándar. Entonces, si no funciona, recuerde que esta es una causa probable y pruebe /dev/null .


Cierre STDOUT primero:

1>&-, >&-

Mira here .


Intentaré algo simple como:

cmd 2> tmp_file && cat tmp_file | grep pattern && rm -f tmp_file