Perché l'output di alcuni programmi Linux non arriva né a STDOUT né a STDERR?


21

Perché l'output di alcuni programmi Linux non arriva né a STDOUT né a STDERR?

In realtà, voglio sapere come acquisire in modo affidabile tutto l'output del programma, indipendentemente dal "flusso" che utilizza. Il problema che ho è che alcuni programmi non sembrano catturare il loro output.

Un esempio è il comando 'time':

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

Perché vedo l'output entrambe le volte? Mi aspettavo che tutto fosse convogliato in / dev / null .

Quale flusso di output utilizza il tempo e come posso inserirlo in un file?

Un modo per aggirare il problema è creare uno script Bash , ad esempio, combine.shcontenente questo comando:

$@ 2>&1

Quindi l'output di 'time' può essere catturato nel modo corretto:

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

(non viene visualizzato alcun output - corretto)

C'è un modo per ottenere ciò che voglio senza usare uno script di combinazione separato?


3
prima dovresti invertire l'ordine: 2>&1 > /dev/nullsignifica "2 ora va dove 1 va (cioè, il terminale, di default), e poi 1 ora va a / dev / null (ma 2 va ancora al terminale!). usa >/dev/null 2>&1per dire "1 ora passa a / dev / null, quindi 2 va dove 1 va (cioè anche a / dev / null). Questo non funzionerà ancora qui poiché il 'tempo' incorporato non verrà reindirizzato, ma è generalmente più corretto (ad esempio funzionerebbe se usi / usr / bin / time). Pensa a "2> & 1" come copiando la "direzione" di 1 in 2, non come 2 andando a 1
Olivier Dulac il

Risposte:


38

Questa domanda è stata affrontata in BashFAQ / 032 . Nel tuo esempio, dovresti:

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

La ragione per cui

time sleep 1 2>/dev/null

non si comporta come ti aspetti perché con quella sintassi, vorrai timeil comando sleep 1 2>/dev/null(sì, il comando sleep 1con stderr reindirizzato a /dev/null). Il builtin timefunziona in questo modo in modo da renderlo effettivamente possibile.

Il bash builtin può effettivamente farlo perché ... beh, è ​​un builtin. Un simile comportamento sarebbe impossibile con il comando esterno timenormalmente situato in /usr/bin. Infatti:

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

Ora, la risposta alla tua domanda

Perché l'output di alcuni programmi linux non arriva né a STDOUT né a STDERR?

è: lo fa, l'output va su stdout o stderr .

Spero che sia di aiuto!


2
è possibile creare altri fd e hanno comandi esplicitamente andare a coloro (es: in script bash: exec 3>/some/file ; ls >&3 ;)
Olivier Dulac

@OlivierDulac Certo, o ancora più semplice con l' coprocintegrato. Ma non è il caso del timebuiltin.
gniourf_gniourf

@ gniourf-gniourf: stavo commentando a causa della tua frase "l'output va a stdout o stderr" ^^
Olivier Dulac il

14

timeÈ stata data una risposta alla tua domanda specifica su builtin, ma ci sono alcuni comandi che non scrivono né su stdoutné su stderr. Un classico esempio è il comando Unix crypt. cryptsenza argomenti crittografa l'input standard stdine lo scrive nell'output standard stdout. Chiede all'utente una password usando getpass(), che per impostazione predefinita genera un prompt /dev/tty. /dev/ttyè l'attuale dispositivo terminale. Scrivere su /dev/ttyha l'effetto di scrivere sul terminale corrente (se ce n'è uno, vedi isatty()).

Il motivo per cui cryptnon è possibile scrivere stdoutè perché scrive in output crittografato stdout. Inoltre, è meglio richiedere /dev/ttyinvece di scrivere in stderrmodo che se un utente reindirizza stdoute stderr, il prompt è ancora visualizzato. (Per lo stesso motivo, cryptnon è possibile leggere la password stdin, poiché viene utilizzata per leggere i dati da crittografare.)


2
+1. Meno rilevante per l'OP, ma più rilevante per tutti coloro che si imbattono in "Perché l'output di alcuni programmi linux non va né a STDOUT né a STDERR?" tramite Google. :-)
ruakh

0

time sleep 1 > /dev/null 2>&1# reindirizza l'output di "sleep" su null. Quindi, "time" scrive il proprio output, senza reindirizzamento. È come " time (sleep 1 > /dev/null 2>&1)".

(time sleep 1) > /dev/null 2>&1 # esegue "time sleep 1", quindi reindirizza il suo output su null.

[]S


-1

Il problema nel tuo caso è che il reindirizzamento funziona in un altro modo. Hai scritto

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

Ciò reindirizza l'output standard /dev/nulle quindi reindirizza l'errore standard sull'output standard.

Per reindirizzare tutto l'output devi scrivere

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

Quindi l'errore standard verrà reindirizzato all'output standard e successivamente verrà reindirizzato a tutto l'output standard (contenente l'errore standard) /dev/null.


Questo non funziona con il built-in bash time. Vedi la mia risposta per alcune spiegazioni.
gniourf_gniourf

+1 perché questa è una risposta utile a una domanda simile. Anche se @Olivier lo spiega meglio nel commento alla domanda sopra.
Will Sheppard,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.