13

我的示例文件

陷阱测试.sh:

#!/bin/bash
trap 'echo trapped' TERM
while :
do
  sleep 1000
done

$ 陷阱测试.sh &

[1] 4280

$ kill %1 <-- 按工作编号杀死有效

终止

被困

$ 陷阱测试.sh &

[1] 4280

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

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

如果我完全删除陷阱语句,kill process-id 会再次起作用吗?

在工作中运行一些 RHEL 2.6.18-194.11.4.el5。我真的对这种行为感到困惑,对吗?

4

3 回答 3

9
kill [pid]

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

kill %1

将 TERM 信号发送到作业#1 的整个进程组,在这种情况下发送到脚本 pid + his children (sleep)。

我已经在睡眠过程和脚本过程中使用 strace 验证了这一点

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

引用最重要的一句话:

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

于 2013-01-07T14:55:53.260 回答
8

这是预期的行为。kill由is发送的默认信号SIGTERM,您正在被您的陷阱捕获。考虑一下:

#!/bin/bash
# traptest.sh

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

while :                 # This is the same as "while true".
do
    a=1
done

(睡眠确实创建了一个新进程,并且我猜我的示例行为更清晰)。

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

应该可以消除%1混乱。

注意:代码示例取自tldp

于 2013-01-07T14:51:44.223 回答
3

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

手册页在SIGNALS部分的最后一段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()andrun_pending_traps()函数。

于 2018-03-20T07:50:27.950 回答