Это старый вопрос, но ни один из ответов здесь не обсуждает использование set -eaka set -o errexitв сценариях обработки пакетов Debian. Использование этой опции обязательно в этих сценариях согласно политике Debian; очевидно, что цель состоит в том, чтобы избежать любой возможности необработанного условия ошибки.
На практике это означает, что вы должны понимать, при каких условиях выполняемые вами команды могут возвращать ошибку, и явно обрабатывать каждую из этих ошибок.
Обычными ошибками являются, например, diff(возвращает ошибку при наличии разницы) и grep(возвращает ошибку при отсутствии совпадения). Вы можете избежать ошибок с явной обработкой:
diff this that ||
echo "$0: there was a difference" >&2
grep cat food ||
echo "$0: no cat in the food" >&2
(Обратите также внимание на то, как мы позаботимся о том, чтобы имя текущего скрипта включалось в сообщение и записывали диагностические сообщения в стандартную ошибку вместо стандартного вывода.)
Если никакая явная обработка не является действительно необходимой или полезной, явно ничего не делайте:
diff this that || true
grep cat food || :
(Использование команды оболочки :no-op немного неясно, но довольно часто встречается.)
Просто чтобы повторить,
something || other
это сокращение для
if something; then
: nothing
else
other
fi
то есть мы явно говорим, что otherдолжен быть запущен тогда и только тогда, когда somethingпроизойдет сбой. Стенограмма if(и другие операторы управления потоком оболочки, такие как while, until) также является допустимым способом обработки ошибки (в самом деле, если бы это было не так, сценарии оболочки с такими параметрами set -eникогда не могли бы содержать операторы управления потоком!)
А также, чтобы быть в явном виде, в отсутствие такого обработчика, это set -eможет привести к немедленному отказу всего сценария с ошибкой, если будет diffнайдено различие или если grepне найдено совпадение.
С другой стороны, некоторые команды не выдают состояние выхода из ошибки, когда вы этого хотите. Обычно проблемными являются команды find(состояние выхода не отражает, были ли файлы фактически найдены) и sed(состояние выхода не показывает, получил ли скрипт какой-либо ввод или действительно выполнил какие-либо команды успешно). В некоторых случаях простой защитой является передача по команде, которая кричит, если нет вывода:
find things | grep .
sed -e 's/o/me/' stuff | grep ^
Следует отметить, что состояние выхода конвейера является состоянием выхода последней команды в этом конвейере. Таким образом, вышеприведенные команды на самом деле полностью маскируют статус findи sedи только сообщают вам, grepнаконец-то, успешно ли это выполнено .
(Bash, конечно, имеет set -o pipefail; но сценарии пакета Debian не могут использовать функции Bash. Политика твердо диктует использование POSIX shдля этих сценариев, хотя это не всегда имело место.)
Во многих ситуациях это то, на что следует обращать особое внимание при кодировании с защитой. Иногда вам нужно, например, просмотреть временный файл, чтобы увидеть, успешно ли завершилась команда, создавшая этот вывод, даже если в противном случае идиома и удобство заставили бы вас использовать конвейер оболочки.