Come stabilire se l'output di un comando o di uno script shell è stdout o stderr


32

Diciamo che eseguo un comando o uno script di shell e questo mi dà output. Senza conoscere gli interni di questo comando o script di shell, come si determina se l'output proviene da stderro stdout?

Ad esempio,

$ ls -ld /
drwxrwxr-t  35 root  admin  1258 Dec 11 19:16 /

vs

ls -ld /test
ls: /test: No such file or directory

Come posso accertare che il primo comando sia stato stampato stdoute il secondo stderr(fatto?)?


1
Quale problema stai cercando di risolvere qui?
Kenster,

3
Temevo che qualcuno lo avrebbe chiesto; nessuno in realtà, per lo più curioso e spero di migliorare la mia comprensione del reindirizzamento.
KM.

7
Potresti mettere il stderredtuo ambiente shell LD_PRELOADper ottenere stdoute stderrin diversi colori. Ecco una domanda correlata in tal senso.
Anko,

Risposte:


18

Non c'è modo di dire una volta che l'output è già stato stampato. In questo caso, entrambi stdoute stderrsono collegati al terminale, quindi le informazioni su quale stream è stato scritto erano già perse quando il testo è apparso sul tuo terminale; sono stati combinati dal programma prima di arrivare al terminal.

Quello che puoi fare, in un caso come sopra, sarebbe eseguire il comando stdoute stderrreindirizzare verso luoghi diversi e vedere cosa succede. Oppure eseguilo due volte, una volta con stdoutreindirizzato a /dev/nulle una volta con stderrreindirizzato a /dev/null, e guarda quale di questi casi porta alla visualizzazione del testo.

Puoi reindirizzare stdouta /dev/nullvirando >/dev/nullalla fine della riga di comando e puoi reindirizzare stderra /dev/nullaggiungendo 2>/dev/null.


9

È possibile reindirizzare stdout utilizzando > filee reindirizzare stderr utilizzando 2> file. Molte moderne shell supportano il reindirizzamento ai comandi, quindi è possibile utilizzare sedper evidenziare quale output proviene da quale stream:

$ ls 2> >(sed 's/^/2: /') > >(sed 's/^/1: /')
1: unity_support_test.0
1: vmwareDnD

$ ls foo 2> >(sed 's/^/2: /') > >(sed 's/^/1: /')
2: ls: cannot access foo: No such file or directory

Molto bella! Sarebbe bello se si potessero evidenziare le linee a colori piuttosto che con il prefisso.
dotancohen,

3
@dotancohen: si può! Ad esempio,(echo "this is stdout"; echo "this is stderr" >&2) > >(sed 's/.*/\x1b[32m&\x1b[0m/') 2> >(sed 's/.*/\x1b[31m&\x1b[0m/')
PM 2Ring

Nota che se c'è un output misto da stdout e stderr, verrà stampato il primo stdout, quindi stderr.
nyuszika7h,

5

Lo annotate-outputscript di Debian devscriptsti consente di farlo in modo selettivo:

$ annotate-output ls -ld /test
14:54:22 -: Started ls -ld /test
14:54:22 E: ls: cannot access /test: No such file or directory
14:54:22 -: Finished with exitcode 2

La seconda colonna indica stdout e stderr con Oe Erispettivamente.

Ci sono alcuni avvertimenti, il principale è come notato nelle altre risposte: non puoi farlo dopo il fatto. Né la shell né il terminale sono a conoscenza di come un programma arbitrario utilizza i suoi descrittori di file, sebbene la shell sia responsabile della loro configurazione iniziale.

Questo metodo utilizza i quindici, la scrittura su un quindicesimo può comportarsi in modo diverso rispetto alla scrittura su un tty e la scrittura su due diversi quindici è decisamente diversa (potenziali tempi / problemi interlacciati). Inoltre, non è adatto per un uso interattivo, ad esempio annotate-output bashnon è un ottimo piano, ma è utile per molti altri scopi. Ci sono molti, molti esempi di script e funzioni shell nelle risposte alle domande correlate sulla colorazione di stdin / stdout / stderr, il più robusto è stderrd che utilizza la modifica di runtime della (maggior parte) programmi per modificare i dati scritti su stderr.

Questa domanda a cui Anko si collega ha buone risposte su quel tema correlato: colorazione dell'output stdout / stderr: posso configurare la mia shell per stampare STDERR e STDOUT in diversi colori?


1
Si noti che è uno bashscript che utilizza while readloop ed esegue un datecomando per ogni riga di stdout o stderr, quindi sarà molto meno efficiente cmd > >(ts '%T O:') 2> >(ts '%T E:')dell'equivalente.
Stéphane Chazelas,

1

A parte le altre risposte, è interessante sottolineare /proc/$PID/fd(anche se non risponde alla domanda):

$ cat > /dev/null 2> /tmp/blablah &
[1] 3073

[1]+  Stopped                 cat > /dev/null 2> /tmp/blablah
$ ls -l /proc/3073/fd
total 0
lrwx------ 1 kampde kampde 64 Feb 24 11:43 0 -> /dev/pts/33
l-wx------ 1 kampde kampde 64 Feb 24 11:43 1 -> /dev/null
l-wx------ 1 kampde kampde 64 Feb 24 11:43 2 -> /tmp/blablah

Come vedi, qui puoi vedere i descrittori di file aperti per un processo. 0è il STDIN, 1è il STDOUTe 2è il STDERR. Se non avessi reindirizzato STDOUT o STDERR, vedresti /dev/pts/33(almeno in questo esempio) perché rimanderebbero al terminale.

note : /proc/$PIDesiste solo per i processi in esecuzione. In questo caso ho usato catsenza argomenti, quindi non termina fino a quando non chiudo il file STDIN. L'ho anche eseguito in background, quindi ho il PID immediatamente per il bene di questo esempio.


0

Non è del tutto chiaro quello che stai chiedendo, ma questo potrebbe aiutare

ls -ld /
echo $?    # Exit status 0 returned because command executed successfully.

ls -ld /test
echo $?    # Non-zero exit status returned -- command failed to execute

fonte

Se il codice di uscita è 0 significa semplicemente che il comando viene eseguito correttamente (stdout), qui puoi trovare significati se il codice di uscita è diverso da 0 (stderr)


Molto interessante! Non avrei mai collegato gli stati di uscita con il reindirizzamento. Lo zero implica stdoute lo zero diverso stderr?
KM.

7
@KM., No. Direi che è fortemente correlato, ma non c'è nulla che impedisca a un programma di scrivere stderre restituire un buon codice di errore o di scrivere stdoute restituire un codice di errore errato. In effetti, prova find /root- supponendo che tu non stia eseguendo come root, dovresti ottenere 2 righe stampate - su "/ root" viene stampato stdoute su "find: / root: autorizzazione negata" stderr. E find restituisce un codice di ritorno errato.
godlygeek,

Il problema di op è chiaro come capire quale sia stdout o stderr.
it_is_a_literature il

0

Di solito STDERR avrà il nome del programma anteposto al messaggio con due punti.

Esempio:

rpm -zq some_utils 
rpm: -zq: unknown option

vs

rpm -ql some_utils 
package some_utils is not installed

-1

Per acquisire e testare l'output di errore:

ls -l test 2>errors
if [ -s errors ]; then echo "There were errors:" && cat errors; fi
rm errors
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.