Если вы действительно не хотите, чтобы вторая команда выполнялась до тех пор, пока первая не станет успешной, то вам, вероятно, нужно использовать временные файлы. Простая версия этого:
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]
Перенаправление «1> & 2» также может быть сокращено до «> & 2»; однако старая версия оболочки MKS неправильно перенаправляла ошибки без предшествующего «1», поэтому я использовал эту однозначную запись для надежности целую вечность.
Это пропускает файлы, если вы что-то прерываете Бомбостойкое (более или менее) программирование оболочки использует:
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
Первая строка прерывания гласит: «Запустите команды» rm -f $tmp.[12]; exit 1
'при возникновении любого из сигналов 1 SIGHUP, 2 SIGINT, 3 SIGQUIT, 13 SIGPIPE или 15 SIGTERM или 0 (когда оболочка выходит по любой причине) ,
Если вы пишете сценарий оболочки, окончательная ловушка должна только удалить ловушку на 0, которая является ловушкой выхода из оболочки (вы можете оставить другие сигналы на месте, так как процесс в любом случае собирается завершиться).
В исходном конвейере для 'c' возможно чтение данных из 'b' до завершения 'a' - это обычно желательно (например, это дает работу нескольким ядрам). Если «b» является фазой «сортировки», то это не будет применяться - «b» должен увидеть все свои входные данные, прежде чем сможет генерировать какой-либо из своих выходных данных.
Если вы хотите определить, какие команды не выполняются, вы можете использовать:
(./a || echo "./a exited with $?" 1>&2) |
(./b || echo "./b exited with $?" 1>&2) |
(./c || echo "./c exited with $?" 1>&2)
Это просто и симметрично - тривиально расширить до 4-х или N-частичного конвейера.
Простые эксперименты с set -e не помогли.