跳转到内容

kill

kill 用于向进程发送信号。名字有误导性 —— 它的本职是发信号,终止进程只是其中最常用的一种。

Terminal window
kill [-信号] PID...
kill -l

不指定信号时发的是 TERM(15) 只能给自己有权限的进程发信号,别人的进程需要 root

信号是内核提供的一种异步通知机制。进程可以为大多数信号注册处理函数,收到时先跑自己的清理逻辑再退出;没注册的就执行内核规定的默认行为。

常用信号:

编号 名字 默认行为 能否被捕获
1 HUP 终止 能。守护进程通常把它约定成「重新读配置」
2 INT 终止 能。等同 Ctrl-C
3 QUIT 终止并转储 core 能。等同 Ctrl-\
9 KILL 立即终止 不能
15 TERM 终止 能。默认信号,给进程留出收尾的机会
18 CONT 继续运行 能
19 STOP 暂停 不能
20 TSTP 暂停 能。等同 Ctrl-Z

KILL 和 STOP 是仅有的两个不能被捕获、阻塞或忽略的信号,由内核直接执行 也正因如此,kill -9 之后进程没有任何机会关文件、写日志、删临时文件、释放锁

选项 说明
-l 列出所有信号名和编号
-<编号> 按编号指定信号,如 -9
-<名字> 按名字指定,如 -TERM、-HUP
-s <名字> 同上,写法更正式
-0 什么都不发,只检查进程是否存在、自己有没有权限

1. 终止进程的正确顺序

Terminal window
kill 1234 # 先发 TERM,让进程自己收尾
kill -9 1234 # 等一会儿仍在,才上 KILL

直接 -9 是坏习惯:数据库来不及刷盘、编辑器留下交换文件、服务留下 pid 文件和锁 给几秒钟,TERM 处理不完再考虑 KILL

2. 让守护进程重读配置

Terminal window
kill -HUP $(cat /var/run/nginx.pid)

HUP 的这个含义是约定俗成的,不是内核规定的,具体行为看程序自己的文档

3. D 状态的进程杀不掉

Terminal window
ps -o pid,stat,comm -p 1234

STAT 显示 D 时进程卡在不可中断的内核态,通常是等一个出问题的 IO 这种情况 -9 也没用,信号要等进程回到用户态才会被处理 只能等 IO 超时,或者去修 IO 那一头(比如断掉的 NFS 挂载),见 ps

4. 按名字发信号

Terminal window
pkill nginx
killall nginx
pkill -u alice -f 'python.*worker'

pkill 和 killall 也是发信号,信号选项的写法和 kill 一致 -f 匹配完整命令行,不加则只匹配进程名 动手之前先用 pgrep -a 同样的条件跑一遍,确认匹配到的就是你想杀的

5. 发给整个进程组

Terminal window
kill -- -1234

PID 写成负数表示进程组号,组内所有进程都会收到 -- 是为了让负号不被当成选项

6. 只检查进程还在不在

Terminal window
kill -0 1234 && echo "还活着"

-0 不发任何信号,只做存在性和权限检查,脚本里常用来轮询等待进程退出

  • man 1 kill
  • man 7 signal(信号的完整列表和语义)