bash函数中的陷阱不会触发

bash函数中的陷阱不会触发,bash,Bash,我有一个相当复杂的bash脚本层次结构,几乎所有东西都依赖于函数。主脚本仅仅是一个shell,它从包含在自己文件中的适当函数(常见函数,如我的输出函数等,以及正在执行的任务的特定函数)中获取源代码 在这个框架中,我有一个特殊的函数,需要正确处理被中断和清理。我在该函数的子函数中处理它的错误清理 i、 e 向主脚本添加陷阱,如下所示: trap "declare -p FUNCNAME ; f_err_cleanup" INT QUIT TERM 失败,因为它不知道f_err_cleanup{}

我有一个相当复杂的bash脚本层次结构,几乎所有东西都依赖于函数。主脚本仅仅是一个shell,它从包含在自己文件中的适当函数(常见函数,如我的输出函数等,以及正在执行的任务的特定函数)中获取源代码

在这个框架中,我有一个特殊的函数,需要正确处理被中断和清理。我在该函数的子函数中处理它的错误清理 i、 e

向主脚本添加陷阱,如下所示:

trap "declare -p FUNCNAME ; f_err_cleanup" INT QUIT TERM
失败,因为它不知道f_err_cleanup{}函数,但陷阱会触发

在my_函数{}中放置一个陷阱永远不会触发,cntl-c只是带着130个退出代码退出该函数(然后主脚本一般地处理该代码)

trap "echo inside trap ; declare -p FUNCNAME" EXIT SIGHUP SIGQUIT SIGINT SIGTERM
上述代码段在执行时失败,如下所示

^C[ ERROR 13 ]  Script "my_script.sh" failed.
下面是来自外部脚本的剪报:

. my_function
my_function "$@" 2>&1 | tee -a "${RUNTIME_LOG}"
declare -i RC=${PIPESTATUS[0]}
if [[ ${RC} -ne 0 ]]; then
    f_err -f -c ${RC} -m "script \"${ME}\"failed\n"
else
    f_out "success\n"
    exit ${RC}
fi
f_err是一个打印错误消息并使用提供的代码退出的函数。如何使陷阱在函数中工作


另外,让外部陷阱执行一个
declare-p FUNCNAME
也会返回FUNCNAME是未知的,尽管据我所知,它应该显示
FUNCNAME[0]=“main”

作为答案发布,因为虽然我没有解决在管道中定义陷阱时让陷阱工作的难题,但我已经解决了我的问题。 因为在本例中,我的管道只是调用
tee
来启用日志记录,所以我能够将管道线路更改为
myu函数“$@”和>>(tee-a“${RUNTIME\u LOG}”)

由于不再涉及管道,函数中的陷阱现在将触发,抛开bash错误处理的可疑性质不谈

在我的_函数{}中放置陷阱永远不会触发

是的。你就是说不出来,因为你用了
echo
来写stdout,而stdout是一个破裂的管道,因为
tee
被你试图处理的sigint杀死了

这是一个MCVE:

#!/bin/bash

myfunction() (
        trap 'mycleanup' INT
        mycleanup() {
                # Write to stderr so we can see it
                echo "Cleaning up" >&2
        }
        echo "doing stuff"
        sleep 42
        echo "done with stuff"
)

myfunction | tee file
(严格来说,函数的显式子shell不是必需的,但有助于防止意外地破坏脚本自身的陷阱)

以下是当您运行并中断它时发生的情况:

$ ./myscript
doing stuff
^CCleaning up

作为更新,我在发布后取得了一些进展。删除`| tee-a“${RUNTIME\u LOG}”`函数调用中的代码段允许按预期从函数中提取陷阱。不幸的是,我们需要捕获该输出以用于审计目的,因此我必须保留该
tee
或将其替换为类似的内容。另一个注意事项:添加
set-o pipefail
会在我的_脚本中获取陷阱。sh触发,但这仍然不利于需要与审核日志一起进行的特定于函数的清理与
set-e
相关的一组陷阱和警告,它们同样适用于错误陷阱。也是相关的,并且是从更接近中性的角度编写的。请特别注意
errtrace
标志(由函数继承的错误陷阱或
set-e
需要)…简言之,bash没有可靠的错误管理机制;在bash中编写代码的人应该实现并仔细审核他们代码的错误处理,就像在C中编写代码的人应该这样做一样。
#!/bin/bash

myfunction() (
        trap 'mycleanup' INT
        mycleanup() {
                # Write to stderr so we can see it
                echo "Cleaning up" >&2
        }
        echo "doing stuff"
        sleep 42
        echo "done with stuff"
)

myfunction | tee file
$ ./myscript
doing stuff
^CCleaning up