如何在Linux上使用bash进行陷阱/杀死?

pol*_*lot 11 bash

我的示例文件

traptest.sh:

#!/bin/bash
trap 'echo trapped' TERM
while :
do
  sleep 1000
done
Run Code Online (Sandbox Code Playgroud)

$ traptest.sh&

[1] 4280

$ kill%1 < - 按作业号码杀死

终止

被困

$ traptest.sh&

[1] 4280

$ kill 4280 < - 按进程ID杀死不起作用?

(蟋蟀的声音,过程没有被杀死)

如果我完全删除了trap语句,kill process-id会再次运行吗?

在工作中运行一些RHEL 2.6.18-194.11.4.el5.我对此行为感到困惑,是不是?

dav*_*vak 8

这是预期的行为.您发送的默认信号killSIGTERM陷阱.考虑一下:

#!/bin/bash
# traptest.sh

trap "echo Booh!" SIGINT SIGTERM
echo "pid is $$"

while :                 # This is the same as "while true".
do
    a=1
done
Run Code Online (Sandbox Code Playgroud)

(睡觉确实创造了一个新的过程,我的例子我的行为更清晰).

因此,如果您traptest.sh在一个终端和kill TRAPTEST_PROCESS_ID另一个终端中运行,运行traptest的终端输出将按Booh!预期进行(并且该进程不会被终止).如果你尝试发送kill -s HUP TRAPTEST_PROCESS_ID,它将杀死traptest进程.

应该可以消除%1困惑.

注意:代码示例取自tldp


Dav*_*rra 8

kill [pid]
Run Code Online (Sandbox Code Playgroud)

将TERM信号专门发送到指定的PID.

kill %1
Run Code Online (Sandbox Code Playgroud)

将TERM信号发送到作业#1的整个进程组,在这种情况下发送到脚本pid +他的孩子(睡眠).

我已经通过strace on sleep进程和脚本进程验证了这一点

无论如何,有人在这里遇到了类似的问题(但使用SIGINT而不是SIGTERM):http://www.vidarholen.net/contents/blog/?p = 34 .

引用最重要的一句话:

kill -INT%1将信号发送到作业的进程组,而不是后台的pid!


Adr*_*ian 6

kill %<jobspec>Davide Berra 解释了和之间的差异kill <PID>,但没有解释这种差异如何导致您观察到的结果。毕竟,Unix 信号处理程序应该几乎立即被调用,那么为什么SIGTERM单独向脚本发送 a 不会触发其陷阱处理程序呢?

手册页在信号部分的最后一段bash解释了原因:

如果bash正在等待命令完成并接收到已设置陷阱的信号,则在命令完成之前不会执行陷阱。

因此,信号立即传递,但处理程序的执行被推迟到sleepexited

因此,与kill %<jobspec>

  • 剧本和sleep收到的SIGTERM
  • bash注册信号,注意到为trap它设置了 a,并将处理程序排队以供将来执行
  • sleep立即退出
  • bash注意到sleep的退出,并运行陷阱处理程序

而与kill <script_PID>

  • 仅收到脚本SIGTERM
  • bash注册信号,注意到为trap它设置了 a,并将处理程序排队以供将来执行
  • sleep1000 秒后退出
  • bash注意到sleep的退出,并运行陷阱处理程序

显然,您不想花足够长的时间来看到最后一点。:)


如果您对具体细节感兴趣,请下载bash源代码并查看trap.c,特别是trap_handler()run_pending_traps()函数。