Почему `trap -`` не работает, когда помещается внутрь функции? - PullRequest
2 голосов
/ 08 февраля 2020

Короткая версия

В скрипте Bash я активирую ловушку, а затем отключаю ее, вызывая trap - EXIT ERR SIGHUP SIGINT SIGTERM. Когда я делаю деактивацию прямо в скрипте, это работает. Однако когда я помещаю точно такую ​​же строку кода в функцию Bash, она игнорируется, т. Е. Ловушка все еще активируется, если позже команда возвращает код выхода, отличный от нуля. Почему?

Длинная версия

У меня есть куча функций для работы с ловушками:

trap_stop()
{
    echo "trap_stop"
    trap - EXIT ERR SIGHUP SIGINT SIGTERM
}

trap_terminate()
{
    local exitCode="$?"
    echo "trap_terminate"
    trap_stop

    local file="${BASH_SOURCE[1]}"
    local stack=$(caller)
    local line="${stack% *}"

    if [ $exitCode == 0 ]; then
        echo "Finished."
    else
        echo "The initialization failed with code $exitCode in $file:${line}."
    fi

    exit $exitCode
}

trap_start()
{
    echo "trap_start"
    trap "trap_terminate $LINENO" EXIT ERR SIGHUP SIGINT SIGTERM
}

При использовании так:

trap_start  # <- Trap started.

echo "Stopping traps."
trap_stop  # <- Trap stopped before calling a command which exits with exit code 2.

echo "Performing a command which will fail."
ls /tmp/missing
exit_code="$?"

echo "The result of the check is $exit_code."

Я получаю следующий вывод:

trap_start
Stopping traps.
trap_stop
Performing a command which will fail.
ls: cannot access '/tmp/missing': No such file or directory
<b>trap_terminate</b>
trap_stop
<b>The initialization failed with code 2 in ./init:41.</b>

Несмотря на то, что была вызвана функция, отключающая ловушку, ловушка все еще срабатывает при вызове ls в каталоге, который не существует.

С другой стороны, когда я заменяю вызов на trap_stop фактическим оператором trap -, например:

trap_start

echo "Stopping traps."
trap - EXIT ERR SIGHUP SIGINT SIGTERM  # <- This statement replaced the call to `trap_stop`.

echo "Performing a command which will fail."
ls /tmp/missing
exit_code="$?"

echo "The result of the check is $exit_code."

, тогда вывод правильный, то есть ловушка не активируется, и я достигаю конец сценария.

trap_start
Stopping traps.
Performing a command which will fail.
ls: cannot access '/tmp/missing': No such file or directory
<b>The result of the check is 2.</b>

Почему перемещение trap - в функцию перестает работать?

1 Ответ

2 голосов
/ 09 февраля 2020

РЕДАКТИРОВАТЬ (любезно предоставлено @KamilCuk): Если ваш bash старше 4.4, обновите свой bash, это может решить проблему.


Я добавил некоторая отладка в вашем коде:

echo "Stopping traps."
trap -p
trap_stop  # <- Trap stopped before calling a command which exits with exit code 2.
trap -p

И получил:

Stopping traps.
trap -- 'trap_terminate 29' EXIT
trap -- 'trap_terminate 29' SIGHUP
trap -- 'trap_terminate 29' SIGINT
trap -- '' SIGFPE
trap -- 'trap_terminate 29' SIGTERM
trap -- '' SIGXFSZ
trap -- '' SIGPWR
trap -- 'trap_terminate 29' ERR
trap_stop
trap -- '' SIGFPE
trap -- '' SIGXFSZ
trap -- '' SIGPWR
trap -- 'trap_terminate 29' ERR

Как видите, часть trap - работает, за исключением для ERR условие.

Через некоторое время man-страницы:

echo "Stopping traps."
set -E
trap_stop  # <- Trap stopped before calling a command which exits with exit code 2.

приводит к:

trap_start
Stopping traps.
trap_stop
Performing a command which will fail.
ls: cannot access '/tmp/missing': No such file or directory
The result of the check is 2.

Соответствующая часть bash(1):

-E Если установлено, любая ловушка ERR наследуется функциями оболочки, подстановками команд и командами, выполняемыми в среде подоболочки. Ловушка ERR обычно не наследуется в таких случаях.

Тем не менее, это похоже на ошибку в bash:

#!/bin/bash

t1()
{
    trap 'echo t1' ERR
}

t2()
{
    trap 'echo t2' ERR
}

t1
false
t2
false

выход:

t1
t1

тогда как я бы ожидал, по крайней мере:

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