在 Linux 上的 bash 中,trap/kill 是如何工作的?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14197470/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 04:11:36  来源:igfitidea点击:

How does trap / kill work in bash on Linux?

bash

提问by polyglot

My sample file

我的示例文件

traptest.sh:

陷阱测试.sh:

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

$ traptest.sh &

$ traptest.sh &

[1] 4280

[1] 4280

$ kill %1 <-- kill by job number works

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

Terminated

trapped

已终止

被困

$ traptest.sh &

$ traptest.sh &

[1] 4280

[1] 4280

$ kill 4280 <-- kill by process id doesn't work?

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

(sound of crickets, process isn't killed)

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

If I remove the trap statement completely, kill process-id works again?

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

Running some RHEL 2.6.18-194.11.4.el5 at work. I am really confused by this behaviour, is it right?

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

采纳答案by Davide Berra

kill [pid]

send the TERM signal exclusively to the specified PID.

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

kill %1

send the TERM signal to the job #1's entire process group, in this case to the script pid + his children (sleep).

将 TERM 信号发送到作业 #1 的整个进程组,在本例中发送到脚本 pid + 他的孩子(睡眠)。

I've verified that with strace on sleep process and on script process

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

Anyway, someone got a similar problem here (but with SIGINT instead of SIGTERM): http://www.vidarholen.net/contents/blog/?p=34.

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

Quoting the most important sentence:

引用最重要的一句话:

kill -INT %1 sends the signal to the job's process group, not the backgrounded pid!

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

回答by davak

This is expected behavior. Default signal sent by killis SIGTERM, which you are catching by your trap. Consider this:

这是预期的行为。发送的默认信号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

(sleep really creates a new process and the behavior is clearer with my example I guess).

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

So if you run traptest.shin one terminal and kill TRAPTEST_PROCESS_IDfrom another terminal, output in the terminal running traptest will be Booh!as expected (and the process will NOTbe killed). If you try sending kill -s HUP TRAPTEST_PROCESS_ID, it will kill the traptest process.

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

Thisshould clear up the %1confusion.

应该消除%1混乱。

Note: the code example is taken from tldp

注意:代码示例取自tldp

回答by Adrian

Davide Berra explained the difference between kill %<jobspec>and kill <PID>, but not howthat difference results in what you observed. After all, Unix signal handlers should be called pretty much instantaneously, so why does sending a SIGTERMto the script alone not trigger its trap handler?

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

The bashman page explains why, in the last paragraph of the SIGNALSsection:

bash手册页解释了为什么在了最后一段SIGNALS部分

If bashis waiting for a command to complete and receives a signal for which a trap has been set, the trap will not be executed until the command completes.

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

So, the signal wasdelivered immediately, but the handler execution was deferred until sleepexited.

因此,信号立即送达,但处理程序的执行被推迟到sleep退出

Hence, with kill %<jobspec>:

因此,与kill %<jobspec>

  • Both the script and sleepreceived SIGTERM
  • bashregistered the signal, noticed that a trapwas set for it, and queued the handler for future execution
  • sleepexited immediately
  • bashnoted sleep's exit, and ran the trap handler
  • 脚本和sleep接收SIGTERM
  • bash注册信号,注意到trap为它设置了a ,并将处理程序排队以备将来执行
  • sleep立即退出
  • bashnotessleep的退出,并运行陷阱处理程序

whereas with kill <script_PID>:

而与kill <script_PID>

  • Only the script received SIGTERM
  • bashregistered the signal, noticed that a trapwas set for it, and queued the handler for future execution
  • sleepexited after 1000 seconds
  • bashnoted sleep's exit, and ran the trap handler
  • 只收到脚本 SIGTERM
  • bash注册信号,注意到trap为它设置了a ,并将处理程序排队以备将来执行
  • sleep1000 秒后退出
  • bashnotessleep的退出,并运行陷阱处理程序

Obviously, you didn't want long enough to see that last bit. :)

显然,您不想看到最后一点。:)



If you're interested in the gory details, download the bashsource codeand look in trap.c, specifically the trap_handler()and run_pending_traps()functions.

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