¿Por qué la salida de algunos programas de Linux no va a STDOUT ni STDERR?

21

¿Por qué la salida de algunos programas de Linux no va a STDOUT ni STDERR?

En realidad, quiero saber cómo capturar de manera confiable todos los resultados del programa, sin importar qué 'transmisión' use. El problema que tengo es que algunos programas no parecen permitir que se capture su salida.

Un ejemplo es el comando 'tiempo':

time sleep 1 2>&1 > /dev/null

real        0m1.003s
user        0m0.000s
sys         0m0.000s

o

time sleep 1 &> /dev/null

real        0m1.003s
user        0m0.000s
sys         0m0.000s

¿Por qué veo la salida en ambas ocasiones? Esperaba que todo se canalizara a / dev / null .

¿Qué flujo de salida usa el tiempo y cómo puedo canalizarlo a un archivo?

Una forma de solucionar el problema es crear un script Bash , por ejemplo, que combine.shcontenga este comando:

$@ 2>&1

Entonces la salida de 'tiempo' puede capturarse de la manera correcta:

combine.sh time sleep 1 &> /dev/null

(no se ve salida - correcto)

¿Hay alguna manera de lograr lo que quiero sin usar un script de combinación por separado?

Will Sheppard
fuente
3
primero debe invertir el orden: 2>&1 > /dev/nullsignifica "2 ahora va a donde va 1 (es decir, el terminal, por defecto), y luego 1 ahora va a / dev / null (¡pero 2 todavía va al terminal!). use >/dev/null 2>&1para decir "1 va ahora a / dev / null, luego 2 va a donde va 1 (es decir, también a / dev / null). Esto todavía no funcionará aquí ya que el 'tiempo' incorporado no se redirigirá, pero es más correcto en general (por ejemplo, funcionaría si usa / usr / bin / time). Piense en "2> & 1" como copiando la "dirección" de 1 en 2, no como 2 yendo a 1
Olivier Dulac

Respuestas:

38

Esta pregunta se aborda en BashFAQ / 032 . En su ejemplo, usted:

{ time sleep 1; } 2> /dev/null

La razón por la cual

time sleep 1 2>/dev/null

no se comporta como espera porque es con esa sintaxis, querrá timeel comando sleep 1 2>/dev/null(sí, el comando sleep 1con stderr redirigido a /dev/null). La construcción timefunciona de esa manera para que esto sea realmente posible.

La bash construcción realmente puede hacer esto porque ... bueno, es una construcción. Tal comportamiento sería imposible con el comando externo timegeneralmente ubicado en /usr/bin. En efecto:

$ /usr/bin/time sleep 1 2>/dev/null
$

Ahora, la respuesta a tu pregunta.

¿Por qué la salida de algunos programas de Linux no va a STDOUT ni STDERR?

es: lo hace, la salida va a stdout o stderr .

¡Espero que esto ayude!

gniourf_gniourf
fuente
2
puede crear otra fd y tienen comandos explícitamente ir a aquellos (por ejemplo: en la escritura del golpe: exec 3>/some/file ; ls >&3 ;)
Olivier Dulac
@OlivierDulac Claro, o incluso más simple con el coprocincorporado. Pero no es el caso de la timeconstrucción.
gniourf_gniourf
@ gniourf-gniourf: Estaba comentando debido a su oración "la salida va a stdout o stderr" ^^
Olivier Dulac
14

Su pregunta en particular sobre el timeorden interna ha sido contestada, pero no son algunos comandos que no escriben ya sea a stdouto stderr. Un ejemplo clásico es el comando Unix crypt. cryptsin argumentos encripta la entrada estándar stdiny la escribe en la salida estándar stdout. Solicita al usuario que use una contraseña getpass(), que por defecto genera una solicitud /dev/tty. /dev/ttyes el dispositivo terminal actual. Escribir en /dev/ttytiene el efecto de escribir en el terminal actual (si hay uno, ver isatty()).

La razón por la cryptque no puede escribir stdoutes porque escribe una salida cifrada stdout. Además, es mejor solicitar en /dev/ttylugar de escribir para stderrque, si un usuario redirige stdouty stderr, todavía se vea el mensaje. (Por la misma razón, cryptno se puede leer la contraseña stdin, ya que se está utilizando para leer los datos para cifrar).

Alok
fuente
2
+1. Menos relevante para el OP, pero más relevante para todos los que se encuentran "¿Por qué la salida de algunos programas de Linux no va ni a STDOUT ni a STDERR?" a través de Google. :-)
ruakh
0

time sleep 1 > /dev/null 2>&1# redirige la salida "sleep" do null. Luego, "tiempo" escribe su propia salida, sin redireccionamiento. Es como " time (sleep 1 > /dev/null 2>&1)".

(time sleep 1) > /dev/null 2>&1 # ejecuta "time sleep 1", luego redirige su salida a nulo.

[] s

Marcio
fuente
-1

El problema en su caso es que la redirección funciona de otra manera. Tu escribiste

time sleep 1 2>&1 > /dev/null

Esto redirige la salida estándar /dev/nully luego redirige el error estándar a la salida estándar.

Para redirigir todos los resultados, debe escribir

time sleep 1 > /dev/null 2>&1 

Luego, el error estándar se redirigirá a la salida estándar y, a continuación, se redirigirá toda la salida estándar (que contiene el error estándar) /dev/null.

Uwe Plonus
fuente
Esto no funciona con el bash incorporado time . Vea mi respuesta para algunas explicaciones.
gniourf_gniourf
+1 porque esta es una respuesta útil a una pregunta similar. Aunque @Olivier lo explica mejor en el comentario a la pregunta anterior.
Will Sheppard