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 tee
in 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 tee
a 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_ios
opzione non sia stata disabilitata, quando un descrittore di file (qui 1) viene reindirizzato più volte per la scrittura, la shell implementa un built-in tee
per 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) tee
può aggiungere a più file contemporaneamente. (3) Perché non solo cat
invece di grep "^"
? (4) il tuo script fallirà quando inizia l'output stderr _stdout_
. (5) Perché?
ls loop
emetterà 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 tee
stdout (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 >>file1
cmd 2>>file1 > >( tee -a file2 >>file1 )
( cmd | tee -a file2 ) >> file1 2>&1
L'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).
sponge
fa:(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 cmd
bypassa 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
file1
linee potrebbero non funzionare.
out+err
e cosaout
significhi qui. Nomi dei file? Stream da reindirizzare?