【发布时间】:2011-12-28 16:43:01
【问题描述】:
我看到很多 shell 脚本可以这样做:
陷阱 cmd 0 1 2 3 13 15 # EXIT HUP INT QUIT PIPE TERM在我目前可以访问的每个shell中,除了0之外的所有陷阱都是多余的,如果简单地指定了陷阱,则会在收到信号后执行cmd:
陷阱命令 0后一种规范是否足够,或者某些 shell 是否需要指定其他信号?
【问题讨论】:
我看到很多 shell 脚本可以这样做:
陷阱 cmd 0 1 2 3 13 15 # EXIT HUP INT QUIT PIPE TERM在我目前可以访问的每个shell中,除了0之外的所有陷阱都是多余的,如果简单地指定了陷阱,则会在收到信号后执行cmd:
陷阱命令 0后一种规范是否足够,或者某些 shell 是否需要指定其他信号?
【问题讨论】:
我认为陷阱 0 在所有情况下都在脚本终止之前执行,因此对于清理功能(如删除临时文件等)很有用。其他信号可以有专门的错误处理,但应该终止脚本(即调用 exit)。
我相信您所描述的实际上会执行 cmd 两次。一次用于信号(例如 SIGTERM),一次用于退出(陷阱 0)。
我认为正确的方法如下(请参阅trap 的 POSIX 规范):
trap "rm tmpfile" 0
trap "exit 1" TERM HUP ...
这可确保在脚本完成后删除临时文件,并允许您在信号上设置自定义退出状态。
注意:无论是否遇到信号,都会调用陷阱 0。
如果您不关心设置退出状态,陷阱 0 就足够了。
【讨论】:
为了确保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
【讨论】:
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 两次。
【讨论】:
trap ... 0 将在 SIGTERM 上执行,也不要假设它不会.制作一个单独的trap "exit 1" SIGTERM ... 以保证它会。