bash函数中的陷阱不会触发

时间:2018-06-07 16:36:14

标签: bash

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

在该框架内,我有一个特殊的功能,需要正确处理中断和清理。我正在处理它在该函数中的子函数中的错误清理 即。

function my_function {
    function f_err_cleanup {
        do error cleanup tasks here
    } #/f_err_cleanup{}
    echo do stuff
    my_other_function -t "some var here"
    my_other_other_function var1 var2 var3
    echo do more stuff
} #/my_function{}

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

trap "declare -p FUNCNAME ; f_err_cleanup" INT QUIT TERM

由于不知道f_err_cleanup {}函数而失败 - 但陷阱触发。

^C./my_script.sh: line 1: declare: FUNCNAME: not found
./my_script.sh: line 1: f_err_cleanup: command not found
[ ERROR 13 ]  Script "my_script.sh" failed.

在my_function {}中放置一个陷阱永远不会触发,而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是一个打印错误消息并使用提供的代码退出的函数。 如何从函数中获取陷阱?

P.S。让外部陷阱执行declare -p FUNCNAME返回FUNCNAME也是未知,即使我理解它应该显示FUNCNAME[0]="main"

2 个答案:

答案 0 :(得分:1)

  

在my_function {}中设置陷阱永远不会触发

是的。您只是无法分辨,因为您使用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

答案 1 :(得分:0)

作为答案发布,因为虽然我没有解决在管道中定义的陷阱工作的难题,但我已经解决了我的问题。 因为在这种情况下我的管道只是调用tee来启用日志记录,所以我能够将管道线路更改为 my_function "$@" &> >( tee -a "${RUNTIME_LOG}" )

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