Come convogliare stderr senza convogliare stdout


24

Come installo il flusso di errore standard senza eseguire il piping del flusso di uscita standard?

So che questo comando funziona, ma scrive anche lo standard.

Command 2>&1 | tee -a $LOG

Come posso ottenere solo l'errore standard?

Nota: quello che voglio da questo è semplicemente scrivere il flusso stderr in un registro e scrivere sia stderr che stdout sulla console.

Risposte:


26

Per fare ciò, utilizzare un descrittore di file aggiuntivo per cambiare stderr e stdout:

find /var/log 3>&1 1>&2 2>&3 | tee foo.file

Fondamentalmente, funziona, o almeno penso che funzioni, come segue:
Le direzioni secondarie vengono valutate da sinistra a destra.

3>&1 Crea un nuovo descrittore di file, 3 un duplicato (copia) di fd 1 (stdout).

1>&2 Rendi stdout (1) un duplicato di fd 2 (stderr)

2>&3 Crea fd 2, un duplicato (copia) di 3, che in precedenza era stato creato una copia di stdout.

Quindi ora stderr e stdout sono cambiati.

| tee foo.file tee duplica il descrittore di file 1 che è stato trasformato in stderr.


Oh, non testato con ksh, funziona con bash ...
Kyle Brandt,

Grazie, funziona anche in ksh. Penso che la maggior parte delle cose pipe e stream siano standard posix.
C. Ross,

"Copia" non è proprio corretto - Vedi la risposta di @ Guasqueño.
Kyle Brandt,

Questo funziona anche in Windows con tee.exeinstallato :)
Acorn

13

Il comando Unix / Linux di Kyle svolge il compito di cambiare STDERR con STDOUT; tuttavia la spiegazione non è del tutto corretta. Gli operatori di reindirizzamento non eseguono alcuna copia o duplicazione, ma semplicemente reindirizzano il flusso in una direzione diversa.

Riscrivere il comando di Kyle spostando temporaneamente 3> & 1 alla fine, renderebbe più semplice la comprensione del concetto:

find /var/log  1>&2  2>&3  3>&1  

Scritto in questo modo, però, Linux mostrerebbe un errore perché & 3 non esiste ancora poiché si trova prima di 3> & 1. 3> qualcosa è un modo per dichiarare (definire) che useremo un terzo tubo, quindi deve essere localizzato prima di far scorrere l'acqua in quel tubo, ad esempio il modo in cui Kyle l'ha scritto. Prova in questo modo solo per divertimento:

((echo "STD1";  anyerror "bbbb"; echo "STD2" ) 3>&1 4>&2 1>&4 2>&3) > newSTDOUT 2> newSTDERR

Non avere modo di fare copie è un peccato. Non puoi fare cose come "3> & 1 3> & 2" con lo stesso comando, perché Linux utilizzerà solo il primo trovato e rifiuta il secondo.

Non ho (ancora) trovato un modo per inviare sia l'errore che l'output normale a un file e anche inviare una copia dell'errore all'output standard con un solo comando. Per esempio, ho un lavoro cron che desidero che entrambi gli output (errore e standard) vadano in un file di registro e che anche l'errore vada fuori per inviare un messaggio e-mail al mio blackBerry. Posso farlo con due comandi usando "tee" ma l'errore non viene visualizzato nel giusto ordine tra la normale riga di output nel file. Questo è il brutto modo in cui ho risolto il problema:

((echo "STD1"; sdfr "bbbb"; echo "STD2" ) 3>&1 1>&2 2>&3 | tee -a log1 ) 2>> log1

Nota che devo usare due volte log1 e devo aggiungere in entrambi i casi, quello primo usando l'opzione "-a" per il comando "tee" e il secondo usando ">>".

Effettuando un registro cat1 si ottiene quanto segue:

STD1
STD2
-bash: sdfr: command not found

Si noti che l'errore non viene visualizzato nella seconda riga come dovrebbe.


Correzione fantastica !
Kyle Brandt,

Controlla zsh e l' mult_iosopzione ( attivata per impostazione predefinita) per essere in grado di reindirizzare un FD più volte.
Tom Hale,

2

secondo la pagina man di ksh (pdksh), puoi semplicemente fare:

Comando 2> & 1> / dev / null | cat -n

cioè duplica stderr su stdout, reindirizza stdout su / dev / null, quindi reindirizza in 'cat -n'

funziona su pdksh sul mio sistema:

$ errorecho () {echo "$ @"> & 2;}

$ errorecho foo
foo

$ errorecho foo> / dev / null # dovrebbe comunque essere visualizzato anche con reindirizzamento stdout
foo

$ errorecho foo 2> & 1> / dev / null | cat -n
     1 pippo
$   

Funziona anche con BusyBox
Udo G

1

L'ho fatto funzionare come mai desiderato da quando ne avevo bisogno e ho perfezionato il tuo comando. ora per me funziona correttamente usando bash 3.2 su debian squeeze usando questo

(echo "foo" 3>&1 1>&2 2>&3 | tee -a log1 ) 2>> log1 >> log2

mentre log1 registra stdout e stderr e log2 registra solo stderr e nient'altro che mette sullo schermo.

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.