是否有必要指定除EXIT之外的陷阱?

时间:2011-11-14 14:08:51

标签: bash shell ksh zsh sh

我看到很多shell脚本:

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

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

trap cmd 0

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

3 个答案:

答案 0 :(得分:20)

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

对于在程序中为它们定义了多个信号处理程序的信号也是如此。

# 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

答案 1 :(得分:18)

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

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

我认为执行此操作的正确方法如下(请参阅trap的POSIX规范):

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

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

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

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

答案 2 :(得分:5)

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