Я спостерігаю якусь дивну поведінку під час використання set -e
( errexit
), set -u
( nounset
) поряд із пастками ERR та EXIT. Вони здаються спорідненими, тому поставити їх в одне питання здається розумним.
1) set -u
не викликає помилок ERR
Код:
#!/bin/bash trap 'echo "ERR (rc: $?)"' ERR set -u echo ${UNSET_VAR}
- Очікується: ERR-пастка викликається, RC! = 0
- Фактично: помилка ERR не викликається, RC == 1
- Примітка:
set -e
не змінює результат
2) Використання set -eu
коду виходу в пастці EXIT 0, а не 1
Код:
#!/bin/bash trap 'echo "EXIT (rc: $?)"' EXIT set -eu echo ${UNSET_VAR}
- Очікується: виклик лову EXIT, RC == 1
- Фактично: викликається пастка EXIT, RC == 0
- Примітка. При використанні
set +e
RC == 1. Пастка EXIT повертає належний RC, коли будь-яка інша команда видає помилку. - Редагувати: На цю тему є публікація SO з цікавим коментарем, який дозволяє припустити, що це може бути пов’язане з використовуваною версією Bash. Тестування цього фрагмента за допомогою Bash 4.3.11 призводить до RC = 1, тож це краще. На жаль, оновити Bash (з 3.2.51) на всіх хостах наразі неможливо, тому нам доведеться придумати якесь інше рішення.
Хтось може пояснити будь-яку з цих форм поведінки?
Пошук цих тем виявився не дуже вдалим, що досить дивно, враховуючи кількість публікацій у налаштуваннях та пастках Баша. Хоча є одна нитка форуму , але висновок досить незадовільний.
set -e
і set -u
вони розроблені спеціально для вбивства скриптованої оболонки. Використання їх в умовах, які можуть викликати їх застосування, знищать сценарій оболонки. Цього не обійти, окрім того, щоб не використовувати їх, а замість цього перевірити на ті умови, коли вони застосовуються в кодовій послідовності. Отже, в основному, ви можете написати хороший оболонку-код, або можете використовувати set -eu
.
-u
б не викликати пастку ERR (це помилка, тому не слід викликати пастку) або код помилки 0, а не 1. Останнє, здається, є помилкою, що вже було виправлено у більш пізній версії, тож це все. Але першу частину досить важко зрозуміти, якщо ви не зрозуміли, що помилки в оцінці оболонки (розширення параметра) та фактичні помилки в командах здаються двома різними речами. Щодо рішення, ну, як ви запропонували, я зараз намагаюся уникати -eu
і перевіряти вручну, коли це необхідно.
(set -u; : $UNSET_VAR)
і подібного. Такі речі теж можуть бути хорошими - ви можете час від &&
часу скидати багато :, (set -e; mkdir dir; cd dir; touch dirfile)
якщо ви отримаєте мій дрейф. Просто це є контрольованими контекстами - коли ви встановлюєте їх як глобальні параметри, ви втрачаєте контроль і стаєте контрольованими. Однак, як правило, є більш ефективні рішення.
bash
зірвався зі стандартом і почав ставити пастки в підрозділи. Пастка, як передбачається, буде виконана в тому ж середовищі, звідки прийшло повернення, алеbash
цього не робило досить довго.