本文要点
- Linux 进程间通信靠信号(Signal),
kill命令的本质就是向进程发信号,而不是字面上的"杀死"。 - 最常用的
SIGTERM(15)与SIGKILL(9)区别:前者让程序自行清理退出(可拦截),后者由内核强制终止(无法拦截)。 SIGSTOP(19)/SIGCONT(18)可以在不销毁进程的前提下挂起/恢复任务,对应kill -STOP与kill -CONT。- 用
&放到后台的进程会随终端关闭被SIGHUP杀掉,nohup与setsid是两种常见"保活"手段,其原理差异值得掌握。 - 掌握了信号与后台任务控制,就能稳健地管理长任务、守护进程与定时清理,是 Linux 运维基本功。
为什么需要信号
在 Linux 中,进程之间需要一种轻量级的通知机制来协调、终止或改变行为,这就是信号(Signal)。它不像消息队列那样传递大量数据,而是一个简单的"数字代号",内核据此触发进程的某个默认动作。无论是你用 Ctrl+C 中断前台程序、用 kill 结束一个进程,还是系统关闭时通知守护进程收尾,背后都是信号在工作。
理解信号,是理解"如何安全地终止、挂起、恢复一个进程"的第一步,也是日常运维里排障和守护长任务的关键。
认识最常见的信号
运行 kill -l 可以看到系统支持的全部信号列表。其中有几个在运维中最常打交道:
| 信号 | 数值 | 默认动作 | 能否拦截 |
|---|---|---|---|
SIGHUP | 1 | 终止进程 | 能 |
SIGINT | 2 | 终止进程(对应 Ctrl+C) | 能 |
SIGKILL | 9 | 立即终止进程 | 不能 |
SIGTERM | 15 | 优雅终止进程 | 能 |
SIGCONT | 18 | 继续被挂起的进程 | 不能 |
SIGSTOP | 19 | 暂停(挂起)进程 | 不能 |
SIGTSTP | 20 | 暂停进程(对应 Ctrl+Z) | 能 |
其中需要重点区分的是 SIGTERM 与 SIGKILL:SIGTERM(15) 是"请你自己收尾退出",程序有机会保存数据、释放资源,甚至主动忽略;而 SIGKILL(9) 由内核直接强制杀掉进程,任何程序都无法拦截,适合处理"已经卡死、无论如何都不退出"的进程。
用 kill 发送信号:优雅终止
kill 命令的名字容易让人误解,它的真正作用是"向指定进程发送信号"。默认发送的是 SIGTERM(15),也就是"请优雅退出"。
sleep 300 &
echo "PID=$!"
kill -15 $PID下面这张截图展示了完整的流程:先启动一个 300 秒的 sleep 长任务,拿到它的 PID,然后发送 SIGTERM(15),进程随即退出:

注意:Ctrl+C对应的是SIGINT(2),只能中断前台任务;对后台任务则必须用kill配合 PID 或作业号来发信号。
kill 既可以用信号数值,也可以用信号名称,二者等价:
kill -15 1234 # 用数值
kill -TERM 1234 # 用名称
kill 1234 # 省略时默认就是 SIGTERM当进程对 SIGTERM 无响应时,才考虑升级为 SIGKILL(9):
kill -9 1234挂起与恢复:SIGSTOP 与 SIGCONT
有时候我们并不是要终止进程,而是想让它暂时停下来,稍后再继续。这正是 SIGSTOP 与 SIGCONT 的用途。SIGSTOP(19) 会把进程挂起(不占用 CPU),SIGCONT(18) 再把它唤醒。
在 ps 输出的 STAT 列中,被挂起的进程状态会从 S(Sleeping,睡眠)变成 T(Stopped,已停止),恢复后又回到 S:
sleep 300 &
PID=$!
kill -STOP $PID # 挂起,状态变 T
kill -CONT $PID # 恢复,状态变回 S下图演示了整个过程,可以清楚看到状态在 S → T → S 之间切换:

Ctrl+Z对应SIGTSTP(20),同样是把前台进程挂起,但它可以被捕获。SIGSTOP则和SIGKILL一样,是内核强制执行的,无法被程序拦截。
后台任务:&、nohup 与 setsid
用 & 把命令放到后台,是一件再常见不过的事。但后台任务有个"坑":当所在的终端会话关闭时,shell 会向它发送 SIGHUP(1),进程默认被终止。这就是为什么明明后台跑着任务,关掉终端后任务就"没了"。
要解决这个问题,常用两种手段:nohup 与 setsid。
nohup:忽略 SIGHUP
nohup 的意思是 "no hangup",它让命令忽略 SIGHUP 信号。配合 & 放到后台,并把输出重定向到文件(避免占用终端),就能保证即使退出终端任务也在继续:
nohup sleep 120 >/tmp/nohup_demo.log 2>&1 &setsid:开启全新会话
setsid 则是让命令脱离当前会话,开启一个新的会话。由于进程一旦脱离原会话,终端关闭时的 SIGHUP 就再也找不到它了,因此同样能达到"保活"效果,而且更彻底。
下面这张截图对比了三种启动方式的进程属性差异。重点关注 PGID(进程组)、SESS(会话)和 STAT 列:

观察输出可以得出清晰结论:
- 普通后台(
sleep &):PGID=SESS=1649799,与父 shell 同属一个会话,终端关闭会被SIGHUP杀掉。 - nohup:
PGID=SESS=1649799,会话没变,只是忽略SIGHUP,所以它仍然"绑定"在原会话里。 - setsid:
PGID=SESS=1649802,相比父进程的1649799是新的一组,STAT显示为Ss(s表示会话首进程),完全独立的会话,终端关闭对它毫无影响。
从长期守护任务的角度看,setsid比nohup更彻底;而如果只是随手在交互终端里避免一次挂断,用nohup就足够轻量。
快速结束同类进程:pkill 与 killall
当需要一次性结束所有符合特征的进程时,逐个查 PID 太麻烦,可以用 pkill 按名称匹配,或用 killall 按精确名称结束:
pkill -x sleep # 结束所有名为 sleep 的进程(-x 精确匹配)
killall sleep # 按进程名结束所有 sleep
pkill -f "node app.js" # 按完整命令行模糊匹配pkill 与 pgrep 是一对好搭档:先用 pgrep 确认要匹配哪些 PID,再用 pkill 精准清理,能有效避免误杀。
常见坑与提示
kill默认发SIGTERM,不是立即杀:对卡死的进程要先用TERM,实在无效再KILL,避免数据损坏。- 区分后台与前台信号:
Ctrl+C/Ctrl+Z只对前台任务有效,后台任务必须用kill/killall/pkill。 nohup不改变会话:它只是忽略SIGHUP。要彻底脱离终端会话,应使用setsid。SIGKILL和SIGSTOP无法拦截:这是内核层强制操作,程序写再多清理代码也无济于事。kill -l的列表随架构略有差异:实时信号(SIGRTMIN起)数量在不同系统上可能不同,但 1~31 的通用信号在所有主流 Linux 上一致。
小结
信号是 Linux 进程控制的核心语言。掌握 SIGTERM/SIGKILL 实现优雅或强制的终止,SIGSTOP/SIGCONT 实现挂起与恢复,再配合 nohup、setsid 等后台保活手段,你就能稳健地管理长任务与守护进程。这些技能在日常运维、脚本编写和服务部署中几乎每天都会用到。
评论 (0)
暂无评论,快来抢沙发吧!