是否需要指定 EXIT 以外的陷阱?

Is it necessary to specify traps other than EXIT?

提问人:William Pursell 提问时间:11/14/2011 更新时间:5/10/2017 访问量:24318

问:

我看到很多 shell 脚本都这样做:

trap cmd 0 1 2 3 13 15 # EXIT HUP INT QUIT PIPE TERM

在我目前可以访问的每个 shell 中,除 0 之外的所有陷阱都是冗余的,如果简单地指定陷阱,则会在收到信号时执行 cmd:

trap cmd 0

后一种规范是否足够,或者某些 shell 是否需要指定其他信号?

bash shell ksh zsh sh

评论


答:

35赞 Brandon Horsley 11/14/2011 #1

我认为在所有情况下,陷阱 0 都是在脚本终止之前执行的,因此对于清理功能(例如删除临时文件等)很有用。其他信号可以有专门的错误处理,但应终止脚本(即调用退出)。

我相信,您所描述的实际上会执行 cmd 两次。一次用于信号(例如 SIGTERM),另一次用于退出(陷阱 0)。

我相信正确的方法是这样做的(参见陷阱的POSIX规范):

trap "rm tmpfile" 0
trap "exit 1" TERM HUP ... 

这可确保在脚本完成时删除临时文件,并允许您在信号上设置自定义退出状态。

注意:无论是否遇到信号,都会调用陷阱 0。

如果您不关心设置退出状态,陷阱 0 就足够了。

评论

1赞 Josh M. 5/26/2023
用作信号似乎记录得很少。而且它似乎没有“捕获”退出信号。例如 在我的脚本中进行了清理,但没有进行.0trap "...cleanup..." 0ERREXIT
10赞 William Pursell 10/19/2012 #2

shell 标准没有指定在接收到未捕获信号时是否执行 0 上的陷阱。特别是,bash 和 dash 的行为不同。在没有为任何信号设置陷阱的情况下,bash 将在收到 SIGTERM 后执行 cmd-list,但 dash 不会。给定 ,bash 在收到 SIGTERM 时执行一次 cmd-list,而 dash 执行 cmd-list 两次。trap cmd-list 0trap cmd-list 0 2

评论

4赞 dubiousjim 10/21/2012
因此,最好的答案是这个和布兰登·霍斯利(Brandon Horsley)的结合:为了可移植性,不要假设它将在SIGTERM上执行,也不要假设它不会。单独做一个,以保证它会。trap ... 0trap "exit 1" SIGTERM ...
26赞 carlo 2/11/2013 #3

为了确保信号处理程序不会被执行两次(这几乎总是不是您想要的),应始终将其设置为在信号处理程序本身的定义中被忽略或重置。EXITEXIT

这同样适用于在程序中为它们定义了多个信号处理程序的信号。

# reset
trap 'excode=$?; cmd; trap - EXIT; echo $excode' EXIT HUP INT QUIT PIPE TERM

# ignore
trap 'excode=$?; trap "" EXIT; cmd; echo $excode' EXIT HUP INT QUIT PIPE TERM

评论

0赞 William Pursell 2/11/2013
这是个好主意。我认为没有必要担心定义了多个陷阱的信号,因为每个信号只能定义一个陷阱。(第二个陷阱将替换第一个陷阱,而不是添加到堆栈中。某些 shell 是否允许定义多个陷阱?
3赞 Ryne Everett 3/23/2015
我和@WilliamPursell一样感到困惑,直到我终于注意到“忽略重置”。