Se davvero non vuoi che il secondo comando proceda fino a quando il primo non è noto per avere successo, allora probabilmente devi usare file temporanei. La versione semplice di questo è:
tmp=${TMPDIR:-/tmp}/mine.$$
if ./a > $tmp.1
then
if ./b <$tmp.1 >$tmp.2
then
if ./c <$tmp.2
then : OK
else echo "./c failed" 1>&2
fi
else echo "./b failed" 1>&2
fi
else echo "./a failed" 1>&2
fi
rm -f $tmp.[12]
Il reindirizzamento "1> & 2" può anche essere abbreviato "> & 2"; tuttavia, una vecchia versione della shell MKS gestiva in modo errato il reindirizzamento dell'errore senza il precedente "1", quindi ho usato quella notazione univoca per l'affidabilità per anni.
Questo perde file se interrompi qualcosa. La programmazione della shell a prova di bomba (più o meno) utilizza:
tmp=${TMPDIR:-/tmp}/mine.$$
trap 'rm -f $tmp.[12]; exit 1' 0 1 2 3 13 15
...if statement as before...
rm -f $tmp.[12]
trap 0 1 2 3 13 15
La prima riga di trap dice "esegui i comandi" rm -f $tmp.[12]; exit 1
quando si verifica uno dei segnali 1 SIGHUP, 2 SIGINT, 3 SIGQUIT, 13 SIGPIPE o 15 SIGTERM, o 0 (quando la shell esce per qualsiasi motivo). Se stai scrivendo uno script di shell, la trappola finale deve solo rimuovere la trappola su 0, che è la trappola di uscita dalla shell (puoi lasciare gli altri segnali sul posto poiché il processo sta per terminare comunque).
Nella pipeline originale, è possibile che "c" legga i dati da "b" prima che "a" abbia finito - questo di solito è desiderabile (ad esempio, dà lavoro a più core). Se "b" è una fase di "ordinamento", questo non si applica: "b" deve vedere tutti i suoi input prima di poter generare uno qualsiasi dei suoi output.
Se vuoi rilevare quali comandi falliscono, puoi usare:
(./a || echo "./a exited with $?" 1>&2) |
(./b || echo "./b exited with $?" 1>&2) |
(./c || echo "./c exited with $?" 1>&2)
Questo è semplice e simmetrico: è banale estenderlo a una pipeline di 4 o N parti.
La semplice sperimentazione con 'set -e' non ha aiutato.
&&|
che significherebbe "continuare il pipe solo se il comando precedente ha avuto successo". Suppongo che potresti anche avere|||
che significherebbe "continuare la pipe se il comando precedente fallisce" (e possibilmente pipe il messaggio di errore come quello di Bash 4|&
).