Это старый вопрос, но ни один из ответов здесь не обсуждает использование set -e
aka 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
для этих сценариев, хотя это не всегда имело место.)
Во многих ситуациях это то, на что следует обращать особое внимание при кодировании с защитой. Иногда вам нужно, например, просмотреть временный файл, чтобы увидеть, успешно ли завершилась команда, создавшая этот вывод, даже если в противном случае идиома и удобство заставили бы вас использовать конвейер оболочки.