Состояние выхода Bash не перехвачено, несмотря на то, что set -e и / или trap активны - PullRequest
6 голосов
/ 06 ноября 2019

Может ли кто-нибудь объяснить поведение bash / set -e во фрагменте кода ниже?

#!/bin/bash

# Comment if you want to test the trap only
set -e -o pipefail -u -E

# Comment if you want to test the set -e only
trap "echo ERROR CAUGHT; exit 12" ERR

function reproduce() {
    # Trigger arithmetic error on purpose
    a=$((1109962735 - hello=12272 + 1))
}

reproduce

# The script is expected to trigger the trap and/or activate the set -e. In both cases it should stop and exit here on error.

status_code=$?
echo "STATUS ${status_code}"
if [[ "${status_code}" != "0" ]];then
    echo "FIXME: why was status code not caught by set -e ?"
    echo "Executing false to prove set -e is still active"
    false
    # If the following is not executed then it proves -e is still active
    echo "set -e not active !!!!!"
    exit 2
fi

Вот что получается при его выполнении:

$ bash reproduce.sh
reproduce.sh: line 8: 1109962735 - hello=12272 + 1: attempted assignment to non-variable (error token is "=12272 + 1")
STATUS 1
FIXME: why was status code it not caught by set -e ?
Executing false to prove set -e is still active
ERROR CAUGHT

Проверка кода выхода

$ echo $?
1

Bash версия

bash --version
GNU bash, version 4.3.48(1)-release (x86_64-pc-linux-gnu)

Воспроизводится также с

GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)

Дополнительные примечания, связанные с комментариями (в любом случае, спасибо всем предложениям):

  • Ловушка комментирования не меняет наблюдаемое странное поведение
  • Удаление set -e для сохранения только ловушки вызывает ловушку либо

Ответы [ 2 ]

3 голосов
/ 06 ноября 2019

Определите reproduce следующим образом, и он будет вести себя так, как вы ожидали.

function reproduce() (
    # Trigger arithmetic error on purpose
    a=$((1109962735 - hello=12272 + 1))
)

Таким образом, ошибка раскрытия будет происходить в подоболочке и вызывать ее выход с ненулевым статусом, таким образом, errexit и trap смогут его перехватить.

Когда вы определите его с помощью фигурных скобок, он будет выполнен в текущей среде выполнения, а синтаксическая ошибка или ошибка расширения предотвратит его завершение;т.е. сдача статуса выхода. Когда это происходит, bash назначит ненулевое значение для $? и продолжит работу, поэтому механизм errexit и ловушка ERR не сработают.

Обычно оболочка POSIX, работающая неинтерактивно, немедленно выходит из системы. из-за ошибки синтаксиса или расширения, но bash этого не делает (если не установлена ​​опция posix), и это является следствием.


По запросу dash-o вот версия, которая устанавливает a для текущей среды выполнения, когда выражение допустимо:

function reproduce() {
    (: $((expression))) && a=$((expression))
}
2 голосов
/ 06 ноября 2019

На поверхности это выглядит так, как будто bash не будет вызывать ловушку из-за различных ошибок SYNTAX. Только когда команда (внешняя, встроенная) выполняется (и возвращает ненулевое значение), ловушка ERR будет срабатывать.

Со страницы руководства:

Еслиsigspec - ERR, команда arg выполняется всякий раз, когда конвейер (который может состоять из одной простой команды), список или составная команда возвращает ненулевое состояние выхода при следующих условиях ...

Ловушка ERR применяется только к ТРУБОПРОВОДУ . Если bash идентифицирует синтаксическую ошибку, она прерывается перед выполнением конвейера, поэтому ловушка НЕТ. Даже если в документации по '-e' указано то же условие (if a pipeline ... exit with non-zero status), наблюдаемое поведение будет другим.

Если вы попробуете другие расширения - например, команда раскрытие-ловушка запущена, так как выполняется конвейерная обработка:

  • a = $ (плохие команды)
  • a = $ ([)

Если использовать, попробуйте различные синтаксические ошибки в арифметическом раскрытии, trapне сработало - не было конвейера.

  • a = $ ((2 +))
  • a = $ ((2 @))

Кроме того, другие ошибки синтаксиса bash не вызывают ловушку: (), [[ ]].

Я не смог найти решение, которое не требует значительных изменений исходного скрипта. Может быть, отправить команду об ошибке / функции в команду bash?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...