Jeśli naprawdę nie chcesz, aby drugie polecenie było kontynuowane, dopóki pierwsze nie zakończy się sukcesem, prawdopodobnie musisz użyć plików tymczasowych. Prosta wersja to:
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]
Przekierowanie „1> & 2” można również skrócić „> & 2”; jednak stara wersja powłoki MKS błędnie radziła sobie z przekierowaniem błędu bez poprzedzającej je cyfry „1”, więc od wieków używam tej jednoznacznej notacji dla zapewnienia niezawodności.
To powoduje wyciek plików, jeśli coś przerwiesz. Programowanie pocisków odpornych na bomby (mniej lub bardziej) wykorzystuje:
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
Pierwsza linia pułapki mówi „uruchom komendy” rm -f $tmp.[12]; exit 1
, gdy wystąpi którykolwiek z sygnałów 1 SIGHUP, 2 SIGINT, 3 SIGQUIT, 13 SIGPIPE lub 15 SIGTERM, lub 0 (gdy powłoka kończy pracę z dowolnego powodu). Jeśli piszesz skrypt powłoki, ostatnia pułapka musi tylko usunąć pułapkę na 0, która jest pułapką wyjściową powłoki (możesz pozostawić inne sygnały na miejscu, ponieważ proces i tak wkrótce się zakończy).
W pierwotnym potoku możliwe jest, że „c” będzie czytać dane z „b” przed zakończeniem „a” - jest to zwykle pożądane (na przykład daje wiele rdzeni do wykonania). Jeśli „b” jest fazą „sortowania”, to nie ma to zastosowania - „b” musi zobaczyć wszystkie swoje dane wejściowe, zanim będzie mógł wygenerować jakiekolwiek dane wyjściowe.
Jeśli chcesz wykryć, które polecenia zawodzą, możesz użyć:
(./a || echo "./a exited with $?" 1>&2) |
(./b || echo "./b exited with $?" 1>&2) |
(./c || echo "./c exited with $?" 1>&2)
Jest to proste i symetryczne - trywialne jest rozszerzenie do potoku 4-częściowego lub N-częściowego.
Proste eksperymentowanie z „set -e” nie pomogło.
&&|
co oznaczałoby „kontynuowanie potoku tylko wtedy, gdy poprzednie polecenie się powiodło”. Przypuszczam, że mógłbyś również mieć,|||
co oznaczałoby „kontynuuj potok, jeśli poprzednie polecenie zawiodło” (i prawdopodobnie potokuj komunikat o błędzie jak Bash 4|&
).