così ho voluto contribuire una risposta del tipo Lesmana di, ma credo che il mio è forse un po 'più semplice e un po' più vantaggiosa soluzione pura-Bourne-shell:
# You want to pipe command1 through command2:
exec 4>&1
exitstatus=`{ { command1; printf $? 1>&3; } | command2 1>&4; } 3>&1`
# $exitstatus now has command1's exit status.
Credo che questo è meglio spiegato dal di dentro out - command1 eseguirà e stampare la sua uscita regolare su stdout (descrittore di file 1), poi una volta che è fatto, printf eseguirà e il codice di uscita del icommand1 di stampa sul suo stdout, ma che stdout viene rediretto nel descrittore di file 3.
Mentre command1 è in esecuzione, il suo stdout viene inviato al comando2 (l'output di printf non lo rende mai a comando2 perché diventa usiamo lo inviamo al descrittore di file 3 invece di 1, che è ciò che legge la pipa). Quindi reindirizziamo l'output di command2 al descrittore di file 4, in modo che rimanga fuori dal descrittore di file 1 - perché vogliamo che il descrittore di file 1 sia gratuito per un po 'più tardi, perché riporteremo l'output di printf sul descrittore di file 3 nel descrittore di file 1 - perché è ciò che la sostituzione di comando (i backtick), catturerà e questo è ciò che verrà inserito nella variabile.
L'ultimo bit di magia è che il primo exec 4>&1
è stato eseguito come comando separato: apre il descrittore di file 4 come copia dello stdout della shell esterna.La sostituzione di comando catturerà tutto ciò che è scritto sullo standard fuori dalla prospettiva dei comandi al suo interno - ma poiché l'output di comando2 sta per il descrittore di file 4 per quanto riguarda la sostituzione di comando, la sostituzione di comando non la cattura - tuttavia una volta ottiene "out" della sostituzione di comando che sta effettivamente andando al descrittore di file complessivo dello script 1.
(Lo exec 4>&1
deve essere un comando separato perché molte shell comuni non lo apprezzano quando si tenta di scrivere su un descrittore di file all'interno di una sostituzione di comando, che viene aperta nel comando "esterno" che utilizza la sostituzione.Questo è il modo più semplice di farlo.)
Puoi guardarlo in modo meno tecnico e più giocoso modo, come se le uscite dei comandi si scavalassero a vicenda: comando1 pipe a comando2, quindi l'output di printf salta sul comando 2 in modo che comando2 non lo prenda, e quindi l'uscita di comando di 2 salta fuori dalla sostituzione di comando proprio come printf atterra appena in tempo per essere catturato dalla sostituzione in modo che finisca nella variabile, e l'output di comando2 vada sul suo buon modo di essere scritto sullo standard output, proprio come in una pipe normale.
Inoltre, come risulta, $?
conterrà ancora il codice di ritorno del secondo comando nel tubo, perché le assegnazioni, sostituzioni di comando e comandi composti variabili sono tutte effettivamente trasparenti per il codice di ritorno del comando al loro interno, quindi lo stato di ritorno di command2 dovrebbe essere propagato - questo, e non dover definire una funzione aggiuntiva, è il motivo per cui penso che questa potrebbe essere una soluzione migliore rispetto a quella proposta da lesmana.
Per i caveat Lesmana cita, è possibile che command1 sarà ad un certo punto finire con descrittori di file 3 o 4, in modo da essere più robusto, si dovrebbe fare:
exec 4>&1
exitstatus=`{ { command1 3>&-; printf $? 1>&3; } 4>&- | command2 1>&4; } 3>&1`
exec 4>&-
Nota che uso comandi composti nel mio esempio, ma sottoshell (utilizzando ()
invece di { }
sarà anche funzionare, anche se può forse essere meno efficiente.)
comandi ereditano i descrittori di file dal processo che li lancia, quindi l'intera seconda linea erediterà descrittore di file di quattro, e il comando composto seguito da 3>&1
erediterà il descrittore di file tre. Quindi lo 4>&-
si assicura che il comando composto interno non erediti il descrittore di file quattro, e 3>&-
non erediterà il descrittore di file tre, quindi comando1 ottiene un ambiente più "pulito", più standard. È anche possibile spostare l'interno 4>&-
accanto allo 3>&-
, ma immagino perché non limitarlo il più possibile.
Non sono sicuro di quanto spesso le cose utilizzino direttamente il descrittore di file tre e quattro: penso che la maggior parte dei programmi temporali utilizzi syscalls che restituiscono descrittori di file non utilizzati al momento, ma a volte scrivono codice nel descrittore di file 3, immagino (potrei immaginare un programma che controlli un descrittore di file per vedere se è aperto, e usarlo se lo è, o comportarsi in modo diverso di conseguenza se non lo è). Quindi quest'ultimo è probabilmente il migliore da tenere a mente e da usare per casi generici.
[["$ {PIPESTATUS [@]}" = ~ [^ 0 \]]] && echo -e "Corrispondenza - errore rilevato" || echo -e "Nessuna corrispondenza - tutto ok" Verranno testati tutti i valori dell'array in una sola volta e verrà visualizzato un messaggio di errore se uno dei valori di pipe restituiti non è zero. Questa è una soluzione generalizzata piuttosto robusta per il rilevamento di errori in una situazione di pipe. –
http://unix.stackexchange.com/questions/14270/get-exit-status-of-process-thats-piped-to-another –