Если вы действительно не хотите, чтобы вторая команда продолжалась до тех пор, пока первая не станет успешной, вам, вероятно, придется использовать временные файлы. Вот простая версия:
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 не помогли.
&&|
что означало бы «продолжать конвейер только в том случае, если предыдущая команда была успешной». Я полагаю, вы также могли бы иметь,|||
что означало бы «продолжить конвейер, если предыдущая команда не удалась» (и, возможно, передать сообщение об ошибке, как в Bash 4|&
).