服务器凌晨三点卡住了,SSH 登上去,进程占着 CPU 不撒手。你打开 ps aux,盯着屏幕上一列列数字,脑子里只有一个问题:
怎么把它干掉?
大多数人面对卡死的服务,第一反应就是 kill -9。,但你可能不知道,kill -9` 其实是最粗暴的最后手段,Linux 系统给你准备了一套更精细的工具。
这篇文章从历史讲起,带你搞清楚 kill、killall、pkill 三条命令的来龙去脉,以及在什么场景下用哪一个。
先聊聊"信号"——进程之间的暗语
在讲命令之前,得先说一件事:kill 这个名字其实有点误导人,它的本质不是"杀死",而是向进程发送一个信号(signal)。
信号是 Unix/Linux 进程间通信的最古老机制之一,就像两个士兵之间发暗号——收到信号的进程自己决定怎么处理。
常用的信号就那么几个:
SIGTERM 是有礼貌的"我走了,你也收拾收拾吧",SIGKILL 是不讲道理的"你现在就得死"——前者进程可以拒绝或延后,后者进程没有任何反抗余地。
所以,kill -9 并不是 kill 的"正确用法",而是当正常方式失效时的核武器。
kill:Unix 1972 年就有的老祖宗
kill 命令的历史出乎意料地长。根据 Unix 历史记录,信号机制最早出现在 Unix Version 2(1972年),到 Unix Version 7(1979年)才完善了完整的信号名称体系。也就是说,这条命令已经活了 50 多年了。
它的用法很简单,只有一个核心逻辑:你得先知道进程的 PID(进程号)。
# 查进程 PIDps aux | grep nginx# 用 PID 发 SIGTERM(默认信号,优雅终止)kill 1234# 发 SIGKILL(强制终止,进程无法拒绝)kill -9 1234# 让 nginx 重新加载配置(不重启进程)kill -HUP 1234# 一次终止多个进程kill 1234 5678 9012
典型场景:定向精准打击
你在服务器上部署了多个 Python 脚本,只想停掉 PID 为 4567 的那一个,不影响其他的。这时候 kill 4567 是最稳妥的选择——手术刀,不是榔头。
kill 的短板
用 kill 的前提是你得先找到 PID,两步走,还容易看花眼。当进程有几十个的时候,这就很折磨人了。这个痛点,催生了后来的两个工具。
killall:按名字终止,来自 psmisc 工具集
killall 让你可以直接用进程名而不是 PID 来终止进程,省去了查 PID 这一步。
但这里有个必须提的陷阱:killall 有两种完全不同的实现。
- • System V(Solaris)版本:
killall 会终止所有你有权限终止的进程,如果是 root 执行,效果等于让系统崩溃——它真的会把整个系统进程全部清光,所以在 Solaris 上它只用于系统关机流程。 - • Linux psmisc 版本:只终止你指定名字的进程,安全可控。
现在 Linux 上用的是 psmisc 版本,行为是安全的。
# 终止所有名为 nginx 的进程killall nginx# 强制终止killall -9 firefox# 忽略大小写匹配进程名killall -I Java# 终止某个用户运行的所有 nginx 进程killall -u www-data nginx# 终止运行超过 10 分钟的 python3 进程killall -o 10m python3# 让 nginx 重载配置(不停服)killall -HUP nginx
典型场景:一键重启所有 Nginx Worker
你修改了 nginx.conf,需要让所有 nginx 进程重新加载配置,但又不想重启服务:
killall -HUP nginx
一条命令,所有 nginx worker 都收到 SIGHUP,优雅地重新读取配置,用户几乎无感知。
killall 的特点:精确匹配
killall 要求进程名完全匹配。比如进程名叫 python3,你敲 killall python 会提示"no process found"。这个特点让它在批量终止同名进程时非常安全,不会误伤。
pkill:1998 年 Solaris 带来的模式匹配革命
pkill 出现于 1998 年的 Solaris 7,最初和 pgrep 配套推出,后来被移植到 Linux(由 procps-ng 包提供)。
它和 killall 的最大区别在于:pkill 支持模糊匹配和正则表达式,不需要写完整进程名。
# 按进程名(支持部分匹配)pkill nginx# 用正则表达式匹配pkill -r "py.*3"# 终止某个用户的所有进程(踢掉一个用户的全部会话)pkill -u xiong# 只终止进程名完整匹配的进程(类似 killall 的行为)pkill -x nginx# 终止占用特定终端的进程pkill -t pts/1# 找到父进程 PID 为 1234 的所有子进程并终止pkill -P 1234# 先用 pgrep 查看会匹配哪些进程,确认后再 pkillpgrep -l "java"pkill java
典型场景一:清理一个用户的所有进程
某个测试账号跑了一堆乱七八糟的进程,你想一键清空:
pkill -u testuser
所有属于 testuser 的进程全部收到 SIGTERM,干净利落。
典型场景二:终止一组相关进程
你的机器上跑了多个版本的 Java 程序,名字分别是 java、java11、java17,你想把它们都停掉:
pkill -r "java"
用正则一网打尽,而 killall java 只会终止名字精确为 java 的那些。
三剑客横向对比
选哪个?一个简单原则:
- • 按进程名批量终止,名字确定 →
killall - • 名字不确定、需要模糊匹配、按用户/终端批量 →
pkill
一个高频误区:kill -9 不是首选
很多人遇到进程不响应,第一反应就是 kill -9。
但 SIGKILL 的问题在于:进程没有机会做清理。数据库来不及刷盘、临时文件来不及删除、网络连接来不及优雅断开——轻则留下一堆脏数据,重则下次启动报错甚至数据损坏。
正确的姿势是先 SIGTERM,等几秒,再 SIGKILL:
# 先礼貌地请它走kill -15 <PID>sleep 5# 如果还在,再强制终止kill -9 <PID>
或者用 pkill/killall 的组合:
pkill nginxsleep 3pkill -9 nginx
这个两步流程,是线上服务优雅下线的标准做法。
kill、killall、pkill 三条命令,背后是 Unix 五十年来对"如何控制进程"这个问题的持续思考。从需要手动查 PID,到按名字匹配,再到支持正则和多维度筛选——工具越来越趁手,但信号机制这套底层语言从未改变。
下次再遇到进程跑飞,记得先 SIGTERM,再考虑 SIGKILL。