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 не є заміною освіти.