set -eзавершает сценарий, если встречается ненулевой код выхода, кроме как при определенных условиях. Кратко говоря об опасности его использования: оно не ведет себя так, как думают люди.
На мой взгляд, это следует рассматривать как опасный хак, который продолжает существовать только в целях совместимости. Оператор set -eне превращает оболочку из языка, использующего коды ошибок, в язык, использующий поток управления, подобный исключению, он просто слабо пытается эмулировать это поведение.
Грег Вулледж может многое сказать об опасностях set -e:
Во второй ссылке есть различные примеры неинтуитивного и непредсказуемого поведения set -e.
Некоторые примеры не интуитивного поведения set -e(некоторые взяты из вики-ссылки выше):
установить -е
х = 0
пусть х ++
echo "x is $ x"
Вышеприведенное приведет к преждевременному завершению работы сценария оболочки, поскольку let x++возвращает 0, которое рассматривается letключевым словом как ложное значение и превращается в ненулевой код завершения. set -eзамечает это и молча завершает сценарий.
установить -е
[-d / opt / foo] && echo "Предупреждение: foo уже установлен. Перезапишет." > & 2
echo "Установка foo ..."
Вышеуказанное работает как положено, выводит предупреждение, если оно /opt/fooуже существует.
установить -е
check_previous_install () {
[-d / opt / foo] && echo "Предупреждение: foo уже установлен. Перезапишет." > & 2
}
check_previous_install
echo "Установка foo ..."
Вышеупомянутое, несмотря на то, что единственная строка была преобразована в функцию, прекратит работу, если /opt/fooее не существует. Это потому, что тот факт, что он работал изначально, является особым исключением из set -eповедения России. Когда a && bвозвращается ненулевое значение, оно игнорируется set -e. Однако теперь, когда это функция, код выхода функции равен коду выхода этой команды, и функция, возвращающая ненулевое значение, автоматически завершит выполнение сценария.
установить -е
IFS = $ '\ n' read -d '' -r -a config_vars <config
Выше будет читать массив config_varsиз файла config. Как мог бы предположить автор, он завершается с ошибкой, если configотсутствует. Поскольку автор, возможно, не намерен, он молча завершается, если configне заканчивается новой строкой. Если бы set -eони здесь не использовались, то config_varsсодержали бы все строки файла независимо от того, заканчивался ли он новой строкой.
Пользователи Sublime Text (и других текстовых редакторов, которые неправильно обрабатывают переводы строк), остерегаются.
установить -е
should_audit_user () {
local group groups = "$ (groups" $ 1 ")"
для группы в $ groups; делать
if ["$ group" = аудит]; затем верните 0; фи
сделанный
возврат 1
}
if should_audit_user "$ user"; тогда
регистратор "Бла"
фи
Автор здесь может разумно ожидать, что если по какой-то причине пользователь $userне существует, то groupsкоманда завершится неудачно, и сценарий завершится, вместо того, чтобы позволить пользователю выполнить некоторую задачу без проверки. Однако в этом случае set -eпрекращение никогда не вступает в силу. Если $userпо какой-либо причине не может быть найдено, вместо завершения сценария should_audit_userфункция просто вернет неверные данные, как если бы они set -eне действовали.
Это относится к любой функции, вызываемой из условной части ifинструкции, независимо от того, насколько глубоко она вложена, где бы она ни была определена, даже если вы set -eснова запускаете ее внутри. Использование ifв любой точке полностью отключает эффект set -eдо тех пор, пока блок условий не будет полностью выполнен. Если автор не знает об этой ловушке или не знает весь свой стек вызовов во всех возможных ситуациях, когда функция может быть вызвана, тогда он напишет ошибочный код, и ложное чувство безопасности, обеспечиваемое, set -eбудет, по крайней мере, частично виноваты.
Даже если автор полностью осознает эту ловушку, обходной путь состоит в том, чтобы писать код так же, как если бы он был написан без него set -e, эффективно делая этот переход менее чем бесполезным; Мало того, что автор должен написать код обработки ошибок вручную, как если бы он set -eне был в силе, но и наличие set -eмогло ввести их в заблуждение, заставляя их думать, что они не обязаны это делать.
Некоторые дополнительные недостатки set -e:
- Это поощряет небрежный код. Об обработчиках ошибок полностью забывают в надежде, что все, что не получилось, сообщит об ошибке некоторым разумным способом. Однако с примерами, подобными
let x++приведенным выше, это не так. Если сценарий неожиданно умирает, он обычно молча, что затрудняет отладку. Если сценарий не умер, и вы ожидали его (см. Предыдущий пункт), то у вас в руках более тонкий и коварный баг.
- Это приводит людей к ложному чувству безопасности. Снова посмотрите
ifточку пули -условия.
- Места, где заканчивается оболочка, не согласуются между оболочками или версиями оболочки. Можно случайно написать скрипт, который ведет себя по-разному в старой версии bash из-за того,
set -eчто он был настроен между этими версиями.
set -eЭто спорный вопрос, и некоторые люди, знающие о проблемах вокруг него, рекомендуют против него, в то время как другие просто рекомендуют позаботиться, пока он активен, чтобы знать подводные камни. Есть много новичков в написании сценариев оболочки, которые рекомендуют set -eвсе сценарии как универсальное средство для выявления ошибок, но в реальной жизни это не работает.
set -e не заменит образование.