Wenn Sie wirklich nicht möchten, dass der zweite Befehl fortgesetzt wird, bis bekannt ist, dass der erste erfolgreich ist, müssen Sie wahrscheinlich temporäre Dateien verwenden. Die einfache Version davon ist:
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]
Die Umleitung '1> & 2' kann auch mit '> & 2' abgekürzt werden. Eine alte Version der MKS-Shell hat die Fehlerumleitung jedoch ohne die vorhergehende '1' falsch behandelt, sodass ich diese eindeutige Notation für die Zuverlässigkeit seit Ewigkeiten verwendet habe.
Dadurch werden Dateien verloren, wenn Sie etwas unterbrechen. Bombensichere (mehr oder weniger) Shell-Programmierung verwendet:
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
In der ersten Trap-Zeile steht "Führen Sie die Befehle aus" rm -f $tmp.[12]; exit 1
, wenn eines der Signale 1 SIGHUP, 2 SIGINT, 3 SIGQUIT, 13 SIGPIPE oder 15 SIGTERM auftritt, oder 0 (wenn die Shell aus irgendeinem Grund beendet wird). Wenn Sie ein Shell-Skript schreiben, muss der letzte Trap nur den Trap auf 0 entfernen, bei dem es sich um den Shell-Exit-Trap handelt (Sie können die anderen Signale an Ort und Stelle belassen, da der Prozess ohnehin kurz vor dem Abschluss steht).
In der ursprünglichen Pipeline ist es möglich, dass 'c' Daten von 'b' liest, bevor 'a' beendet ist - dies ist normalerweise wünschenswert (es gibt zum Beispiel mehrere Kerne Arbeit zu erledigen). Wenn 'b' eine 'Sortierphase' ist, gilt dies nicht - 'b' muss alle Eingaben sehen, bevor es eine Ausgabe erzeugen kann.
Wenn Sie feststellen möchten, welche Befehle fehlschlagen, können Sie Folgendes verwenden:
(./a || echo "./a exited with $?" 1>&2) |
(./b || echo "./b exited with $?" 1>&2) |
(./c || echo "./c exited with $?" 1>&2)
Dies ist einfach und symmetrisch - es ist trivial, sich auf eine 4-teilige oder N-teilige Pipeline zu erstrecken.
Einfaches Experimentieren mit 'set -e' hat nicht geholfen.
&&|
was bedeuten würde "die Pipe nur fortsetzen, wenn der vorhergehende Befehl erfolgreich war". Ich nehme an, Sie könnten auch haben,|||
was bedeuten würde "die Pipe fortsetzen, wenn der vorhergehende Befehl fehlgeschlagen ist" (und möglicherweise die Fehlermeldung wie bei Bash 4 weiterleiten|&
).