Ловушка Bash не вызывается в функции, вызываемой из цикла - PullRequest
2 голосов
/ 11 апреля 2019

Ловушка, вызываемая в функции, вызываемой из цикла, не вызывается.Ловушка работает должным образом, если вызывается в теле цикла напрямую.Та же функция, если вызывается вне цикла, вызывает trap.

#!/bin/bash

function error_handler() #---------------------
{
    echo "ERROR STATUS: $?"
    echo "ERROR COMMAND: $BASH_COMMAND"
    echo "ERROR STACK:"
    caller
    echo "---------- end of stack dump ----------"
    exit 1
}

function func()
{
    echo "..inside func( $1)"
    if false
    then
        true
        rv=0
    else
        false
        rv=1
    fi
    echo "..returning from func( $1), rv=$rv"
    return $rv
}

set -o errtrace -o errexit
trap error_handler ERR

for N in 1 2 ; do

    echo -e "\nbegin loop $N"
    if func $N
    then
        echo "result of func($N): success"
    else
        echo "result of func($N): failed"
    fi
    echo "loop $N is done"
    false

done

func 1
func 2

Фактический скрипт, выполняющий результат выше:

begin loop 1
..inside func( 1)
..returning from func( 1), rv=1
result of func(1): failed
loop 1 is done
ERROR STATUS: 1
ERROR COMMAND: false
ERROR STACK:
41 ./a.sh
---------- end of stack dump ----------

, но я ожидаю, что trap от строки false внутри func(), а не false в конце программы.Давайте закомментируем false в конце.Результат:

begin loop 1
..inside func( 1)
..returning from func( 1), rv=1
result of func(1): failed
loop 1 is done

begin loop 2
..inside func( 2)
..returning from func( 2), rv=1
result of func(2): failed
loop 2 is done
..inside func( 1)
ERROR STATUS: 1
ERROR COMMAND: false
ERROR STACK:
21 ./a.sh
---------- end of stack dump ----------

Теперь внутри func() была вызвана ловушка, но не в цикле 1!И цикл 1, и цикл 2 завершены без ловушки.Это было func 1 после того, как функция вернулась, что вызвало ловушку.Слишком поздно.

Почему?

1 Ответ

2 голосов
/ 11 апреля 2019

Виноват не цикл, а оператор if здесь:

if func $N

Когда вы используете func в тесте в операторе if, ERR прерывания приостанавливаютсяна всю продолжительность теста.Ошибки, возникающие внутри func(), не вызывают ERR ловушек и не приводят к выходу оболочки, если включена errexit.

Цитирование справочной страницы bash :

Ловушка ERR не выполняется, если сбойная команда является частью списка команд, следующих сразу за ключевым словом while или until, частью теста в операторе if, часть команды, выполняемой в списке && или ||, за исключением команды, следующей за последним && или ||, любой команды в конвейере, кроме последней, или если возвращается значение командыинвертировано с использованием !.Этим же условиям подчиняется опция errexit (-e).

...