Точна мова, що використовується в єдиній специфікації UNIX для опису значенняset -e
:
Якщо ця опція ввімкнена, якщо проста команда не спрацьовує з будь-якої з причин, перелічених у Послідках помилок оболонки або повертає значення статусу виходу> 0, і не є [умовною чи заперечною командою], оболонка негайно вийде.
Існує неоднозначність щодо того, що відбувається, коли така команда відбувається в нижній частині . З практичної точки зору, все, що використовується в допоміжній оболонці, - це вихід і повернення ненульового статусу до батьківської оболонки. Чи вийде вихідна оболонка у свою чергу, залежить від того, чи цей статус ненульового значення перетворюється на просту команду, яка не працює в батьківській оболонці.
Один з таких проблемних випадків - той, з яким ви стикалися: ненульовий стан повернення від підстановки команди . Оскільки цей статус ігнорується, це не спричиняє вихід батьківської оболонки. Як ви вже виявили , спосіб врахування статусу виходу полягає у використанні підстановки команд у простому призначенні : тоді статус виходу присвоєння - це статус виходу останньої підстановки команди у призначенні .
Зауважте, що це буде виконуватись за призначенням, лише якщо є одна заміна команд, оскільки враховується лише статус останньої заміни. Наприклад, наступна команда є успішною (як відповідно до стандарту, так і в кожній реалізації, яку я бачив):
a=$(false)$(echo foo)
Ще один випадок , щоб спостерігати за це явні подоболочкі : (somecommand)
. Згідно з вищезгаданою інтерпретацією, додаткова оболонка може повернути ненульовий статус, але оскільки це не проста команда в батьківській оболонці, батьківська оболонка повинна продовжуватися. Насправді всі снаряди, про які я знаю, змушують батьків повернутися в цей момент. Хоча це корисно у багатьох випадках, наприклад, (cd /some/dir && somecommand)
коли круглі дужки використовуються для збереження операції, такої як поточна зміна каталогів на локальну, вона порушує специфікацію, якщо set -e
вона вимкнена в підпакеті, або якщо підпрограшка повертає ненульовий статус таким чином, не припиняв би його, наприклад, використання !
справжньої команди. Наприклад, всі золи, bash, pdksh, ksh93 та zsh виходять, не відображаючи foo
наступних прикладів:
set -e; (set +e; false); echo "This should be displayed"
set -e; (! true); echo "This should be displayed"
Але жодна проста команда не відбулася, поки set -e
вона діяла!
Третій проблемний випадок - елементи нетривіального трубопроводу . На практиці всі оболонки ігнорують відмови елементів трубопроводу, крім останнього, і виявляють одну з двох поведінки щодо останнього елемента трубопроводу:
- ATT ksh і zsh, які виконують останній елемент конвеєра в батьківській оболонці, діють як завжди: якщо проста команда не працює в останньому елементі конвеєра, оболонка виконує цю команду, яка, як буває, є батьківською оболонкою, виходи.
- Інші оболонки наближають поведінку шляхом виходу, якщо останній елемент трубопроводу повертає ненульовий статус.
Як і раніше, відключення set -e
або використання заперечення в останньому елементі трубопроводу призводить до повернення ненульового статусу таким чином, що він не повинен закінчувати оболонку; снаряди, відмінні від ATT ksh і zsh, тоді вийдуть.
pipefail
Параметр Баша змушує трубопровід негайно вийти, set -e
якщо будь-який з його елементів повертає ненульовий статус.
Зауважте, що як подальше ускладнення, bash вимикається set -e
в підрозділах, якщо він не знаходиться в режимі POSIX ( set -o posix
або POSIXLY_CORRECT
в середовищі, коли запускається bash).
Все це показує, що специфікація POSIX, на жаль, погано справляється із зазначенням -e
параметра. На щастя, існуючі снаряди здебільшого послідовні у своїй поведінці.