在从循环调用的函数中未调用Bash陷阱

在从循环调用的函数中未调用Bash陷阱,bash,function,bash-trap,Bash,Function,Bash Trap,在从循环内部调用的函数中调用的陷阱不会被调用。如果在循环体中直接调用,则陷阱可以正常工作。如果在循环外部调用相同的函数,则调用陷阱 #!/bin/bash function error_handler() #--------------------- { echo "ERROR STATUS: $?" echo "ERROR COMMAND: $BASH_COMMAND" echo "ERROR STACK:" caller echo "--------

在从循环内部调用的函数中调用的陷阱不会被调用。如果在循环体中直接调用,则陷阱可以正常工作。如果在循环外部调用相同的函数,则调用陷阱

#!/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
运行上述脚本的实际结果:

开始循环1
…内部函数(1)
..从func(1)返回,rv=1
func(1)的结果:失败
循环1完成
错误状态:1
错误命令:false
错误堆栈:
41./a.sh
----------堆栈结束转储----------
但是我希望陷阱来自
func()
中的
false
行,而不是程序末尾的
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
,调用了一个陷阱。太晚了


为什么?

罪魁祸首不是循环,而是这里的
if
语句:

if func $N
当您在
if
语句的测试中使用
func
时,
ERR
陷阱将在整个测试期间暂停。在
func()
内发生的错误不会触发
ERR
陷阱,如果启用了
errexit
,也不会导致shell退出

引述:

如果失败的命令是紧跟在
之后的命令列表的一部分,而
直到
关键字,
if
语句中测试的一部分,则不会执行
ERR
陷阱,在
&&
|
列表中执行的命令的一部分,除了最后一个
&&&
|
之后的命令,管道中除最后一个命令外的任何命令,或者如果命令的返回值正在使用
反转。这些条件与
errexit
-e
)选项所遵循的条件相同


我阅读了手册页面,但是没有明显的迹象表明嵌套命令的陷阱也被挂起。谢谢你的澄清。我可以重写我的示例代码。如果func$N,我可以用
func$N替换行
;如果[[$?-eq 0]]
,那么如何在函数
func
中实现已启用的陷阱?是否只有一种方法:移动
func
以分离脚本
func.sh
?放置另一个
set-o errtrace-o errexit;trap error\u handler ERR
到函数的开头
func
没有帮助。我同意,这并不明显。我最近才确切地了解了“测试的一部分”的含义,即在测试完成之前,错误检查是全局暂停的<代码>函数$N;如果…
足以在
func
中启用陷阱。