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

Wil*_*ell 33 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是否需要指定其他信号?

小智 21

为了确保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
Run Code Online (Sandbox Code Playgroud)

  • 我和@WilliamPursell一样困惑,直到我终于注意到"忽略**或**重置". (2认同)

Bra*_*ley 19

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

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

我相信这样做的正确方法如下(参见POSIX规范trap):

trap "rm tmpfile" 0
trap "exit 1" TERM HUP ... 
Run Code Online (Sandbox Code Playgroud)

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

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

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


Wil*_*ell 6

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两次.

  • 所以最好的答案是这个和Brandon Horsley的组合:为了便携性,不要假设`trap ... 0`将在SIGTERM上执行,并且不要假设它不会.制作一个单独的"陷阱"退出1"SIGTERM ..."以保证它会. (2认同)