Come posso raggiungere
cmd >> file1 2>&1 1>>file2
Cioè, lo stdout e lo stderr dovrebbero reindirizzare a un file (file1) e solo lo stdout (file2) dovrebbe reindirizzare a un altro (entrambi in modalità append)?
Come posso raggiungere
cmd >> file1 2>&1 1>>file2
Cioè, lo stdout e lo stderr dovrebbero reindirizzare a un file (file1) e solo lo stdout (file2) dovrebbe reindirizzare a un altro (entrambi in modalità append)?
Risposte:
Il problema è che quando si reindirizza l'output, non è più disponibile per il reindirizzamento successivo. È possibile reindirizzare teein una subshell per mantenere l'output per il secondo reindirizzamento:
( cmd | tee -a file2 ) >> file1 2>&1
o se ti piace vedere l'output nel terminale:
( cmd | tee -a file2 ) 2>&1 | tee -a file1
Per evitare di aggiungere lo stderr del primo teea file1, dovresti reindirizzare lo stderr del tuo comando su un descrittore di file (ad es. 3), e successivamente aggiungerlo di nuovo a stdout:
( 2>&3 cmd | tee -a file2 ) >> file1 3>&1
# or
( 2>&3 cmd | tee -a file2 ) 3>&1 | tee -a file1
(grazie @ fra-san)
Con zsh:
cmd >& out+err.log > out.log
In modalità append:
cmd >>& out+err.log >> out.log
In zsh, e purché l' mult_iosopzione non sia stata disabilitata, quando un descrittore di file (qui 1) viene reindirizzato più volte per la scrittura, la shell implementa un built-in teeper duplicare l'output su tutte le destinazioni.
cmd >& file1 > file2
Puoi: taggare stdout (usando un sed UNBUFFERED, cioè:), sed -u ...anche stderr passa a stdout (senza tag, dato che non ha passato quel tag tagging), e quindi essere in grado di differenziare i 2 nel file di registro risultante.
Quanto segue: è lento (può essere seriamente ottimizzato, usando ad esempio uno script perl anziché il mentre ...; do ...; fatto, ad esempio, che genererà sottotitoli e comandi in ogni riga!), Strano (sembra che io abbia bisogno dei 2 {} stadi per rinominare uno stdout e poi nell'altro aggiungere lo "falled" allo stderr), ecc. Ma è: una " prova del concetto ", che cercherà di mantenere ordina l'output il più possibile di stdout e stderr:
#basic principle (some un-necessary "{}" to visually help see the layers):
# { { complex command ;} | sed -e "s/^/TAGstdout/" ;} 2>&1 | read_stdin_and_redispatch
#exemple:
# complex command = a (slowed) ls of several things (some existing, others not)
# to see if the order of stdout&stderr is kept
#preparation, not needed for the "proof of concept", but needed for our specific exemple setup:
\rm out.file out_AND_err.file unknown unknown2
touch existing existing2 existing3
#and the (slow, too many execs, etc) "proof of concept":
uniquetag="_stdout_" # change this to something unique, that will NOT appear in all the commands outputs...
# avoid regexp characters ("+" "?" "*" etc) to make it easy to remove with another sed later on.
{
{ for f in existing unknown existing2 unknown2 existing3 ; do ls -l "$f" ; sleep 1; done ;
} | sed -u -e "s/^/${uniquetag}/" ;
} 2>&1 | while IFS="" read -r line ; do
case "$line" in
${uniquetag}*) printf "%s\n" "$line" | tee -a out_AND_err.file | sed -e "s/^${uniquetag}//" >> out.file ;;
*) printf "%s\n" "$line" >> out_AND_err.file ;;
esac;
done;
# see the results:
grep "^" out.file out_AND_err.file
ls unknown) per stampare qualcosa su stderr? >&2 echo "error"andrebbe bene. (2) teepuò aggiungere a più file contemporaneamente. (3) Perché non solo catinvece di grep "^"? (4) il tuo script fallirà quando inizia l'output stderr _stdout_. (5) Perché?
ls loopemetterà sia su stdout che su stderr, mixati (in alternativa), in un ordine controllato; in modo che possiamo verificare che abbiamo mantenuto quell'ordinamento stderr / stdout nonostante il tagging di stdout 2): gnu tail, forse, ma no coda regolare (ex, su aix.). 3): grep "^" mostra anche entrambi i nomi dei file. 4): può essere modificato dalla variabile. 5): l'esempio contorto funziona su vecchi osi (ex, vecchio aix) dove l'ho provato (nessun perl disponibile).
uniquetag="banaNa11F453355B28E1158D4E516A2D3EDF96B3450406...)
Se l'ordine di output deve essere: stdout, allora stderr ; non esiste una soluzione solo con il reindirizzamento.
Lo stderr deve essere archiviato in un file temporale
cmd 2>>file-err | tee -a file1 >>file2
cat file-err >> file1
rm file-err
Descrizione:
L'unico modo per reindirizzare un output (un fd come stdout o stderr) su due file è riprodurlo. Il comando teeè lo strumento corretto per riprodurre il contenuto di un descrittore di file. Quindi, un'idea iniziale di avere un output su due file sarebbe quella di usare:
... | tee file1 file2
Ciò riproduce lo stdin di tee su entrambi i file (1 e 2) lasciando l'output di tee ancora inutilizzato. Ma dobbiamo aggiungere (usare -a) e solo una copia. Questo risolve entrambi i problemi:
... | tee -a file1 >>file2
Per fornire teestdout (quello da ripetere) dobbiamo consumare stderr direttamente dal comando. In un modo, se l'ordine non è importante (l'ordine di output (molto probabilmente) sarà preservato come generato, qualunque sia l'output prima verrà memorizzato per primo). O:
cmd 2>>file1 | tee -a file2 >>file1cmd 2>>file1 > >( tee -a file2 >>file1 )( cmd | tee -a file2 ) >> file1 2>&1L'opzione 2 funziona solo in alcune shell. L'opzione 3 usa una sottostruttura aggiuntiva (più lenta) ma usa i nomi dei file solo una volta.
Ma se stdout deve essere il primo (qualunque sia l'output dell'ordine generato) dobbiamo archiviare stderr per aggiungerlo al file alla fine (prima soluzione pubblicata).
spongefa:(cmd | tee -a out >> out+err) 2>&1 | sponge >> out+err
Nell'interesse della diversità:
Se il tuo sistema supporta /dev/stderr, quindi
(cmd | tee -a /dev/stderr) 2>> file1 >> file2
funzionerà. L'output standard di cmd
viene inviato sia allo stdout che allo stderr della pipeline. L'errore standard del cmdbypassa il tee
ed esce lo stderr della pipeline.
Così
cmd, ecmd, mescolati.È quindi una semplice questione di inviare quei flussi ai file corretti.
Come in quasi tutti gli approcci come questo (inclusa la risposta di Stéphane ), le
file1linee potrebbero non funzionare.
out+erre cosaoutsignifichi qui. Nomi dei file? Stream da reindirizzare?