set -e
припиняє сценарій, якщо зустрічається ненульовий код виходу, за винятком певних умов. Підсумовуючи небезпеку його використання кількома словами: він не веде себе так, як думають люди.
На мою думку, це слід розглядати як небезпечний злом, який продовжує існувати лише для сумісності. Оператор set -e
не перетворює оболонку з мови, яка використовує коди помилок, у мову, яка використовує контрольний потік, що нагадує виняток, вона просто погано намагається наслідувати цю поведінку.
Грег Wooledge має багато сказати про небезпеку set -e
:
У другій ланці є різні приклади неінтуїтивної та непередбачуваної поведінки Росії set -e
.
Деякі приклади неінтуїтивної поведінки set -e
(деякі взяті з посилання wiki вище):
встановити -е
x = 0
нехай 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 () {
локальні групові групи = "$ (групи" $ 1 ")"
для групи в $ групах; робити
if ["$ group" = аудит]; потім повернути 0; фі
зроблено
повернути 1
}
if повинен_audit_user "$ user"; тоді
лісоруб 'Blah'
фі
Тут автор може обґрунтовано очікувати, що якщо з якихось причин користувача $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
не є заміною освіти.