You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

kill -2/INT的进程终止机制及pkill -2无法终止b.sh的技术疑问

关于kill -2/kill -INTpkill -2的疑问解答

一、kill -2(也就是kill -INT)是怎么终止进程的?

首先得明确:kill -2发送的是SIGINT信号(信号编号2),这个信号就是我们平时按键盘Ctrl+C时触发的中断信号。

它的工作流程大概是这样的:

  • 当你执行kill -2 <进程PID>,操作系统内核会把SIGINT信号传递给目标进程。
  • 进程收到这个信号后,默认的行为是终止运行——但这不是强制的:如果进程提前通过代码注册了SIGINT的信号处理函数,它可以选择忽略信号、执行清理逻辑(比如保存临时数据、关闭文件)后再退出,甚至完全不终止。
  • kill -9(SIGKILL)不同,SIGINT是一种“友好”的终止信号,给了进程收尾的机会,而SIGKILL是强制杀死,进程根本没机会处理就会被内核终止。

二、pkill -2的作用,以及为什么两个脚本的终止结果不一样?

先说说pkill -2的作用

pkill是一个基于进程名(或其他属性)匹配进程的工具,pkill -2 <进程名>的意思就是:找到所有名字匹配目标的进程,给它们发送SIGINT信号。它和kill -2的核心区别只是匹配方式:kill需要你明确指定进程PID,而pkill帮你自动匹配进程名对应的PID,再发信号。

为什么a.sh能被成功终止,b.sh却看起来不行?

我们拆解两个脚本的运行状态来看:

  1. a.sh的情况
    a.sh里执行的read是bash的内置命令——也就是说,这个命令是直接在bash进程内部运行的,没有启动子进程。当你执行pkill -2 a.sh,SIGINT信号直接发给了a.sh对应的bash进程,bash收到信号后会立刻终止read命令,整个脚本也就跟着退出了,所以你能看到立刻终止的效果。

  2. b.sh的情况
    b.sh的循环里有sleep 1s,这是一个外部命令——bash会启动一个独立的子进程来执行sleep,然后自己进入等待状态,等着sleep执行完毕再继续循环。

    这里的关键是:bash脚本在等待外部子进程运行时,会暂时忽略SIGINT信号,直到子进程结束才会处理收到的SIGINT。所以你执行pkill -2 b.sh后,bash进程不会立刻响应,得等当前的sleep跑完那1秒,才会处理之前收到的SIGINT,脚本才会终止——并不是真的无法终止,只是有延迟。

    如果想让b.sh立刻终止,可以加-f参数:pkill -2 -f b.sh-f会匹配整个命令行(而不只是进程名),这样sleep子进程也会被匹配到,SIGINT信号会同时发给bash父进程和sleep子进程,sleep收到信号后立刻终止,bash也就会马上处理SIGINT并退出脚本了。


内容的提问来源于stack exchange,提问作者xiang fang

火山引擎 最新活动