kill -2/INT的进程终止机制及pkill -2无法终止b.sh的技术疑问
kill -2/kill -INT和pkill -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却看起来不行?
我们拆解两个脚本的运行状态来看:
a.sh的情况:
a.sh里执行的read是bash的内置命令——也就是说,这个命令是直接在bash进程内部运行的,没有启动子进程。当你执行pkill -2 a.sh,SIGINT信号直接发给了a.sh对应的bash进程,bash收到信号后会立刻终止read命令,整个脚本也就跟着退出了,所以你能看到立刻终止的效果。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




