Я наблюдаю странное поведение при использовании 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 trap, RC == 1
- Фактически: ловушка EXIT называется, RC == 0
- Примечание. При использовании
set +e
RC == 1. Ловушка EXIT возвращает правильный RC, когда любая другая команда выдает ошибку. - Редактировать: есть SO сообщение на эту тему с интересным комментарием, предполагающим, что это может быть связано с используемой версией Bash. Тестирование этого фрагмента с помощью Bash 4.3.11 дает RC = 1, так что это лучше. К сожалению, в настоящее время обновление Bash (с версии 3.2.51) на всех хостах невозможно, поэтому нам нужно найти какое-то другое решение.
Кто-нибудь может объяснить любое из этих поведений?
Поиск по этим темам был не очень успешным, что довольно удивительно, учитывая количество постов в настройках и ловушках Bash. Хотя есть одна ветка форума , но вывод довольно неудовлетворительный.
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
она этого не делала довольно давно.