讲解
kill 命令的名字有误导性:它的本质是向进程「发信号」,结束进程只是最常用的一种。信号是操作系统给进程的通知,常见几个:SIGTERM(15)礼貌地请求退出——进程可以捕获它,做完保存数据、关闭连接等收尾工作再走;SIGKILL(9)由内核直接处决,进程没有任何反抗和收拾残局的机会;SIGINT(2)就是你在终端按 Ctrl+C 发出的中断;SIGHUP(1)传统上是「终端挂起」,如今常被服务程序约定为「重新加载配置」。kill -l 可以列出全部信号。
用法是 kill -信号 PID:kill 1234 默认发 SIGTERM;进程不听话时再升级 kill -9 1234。按名字批量操作有两个工具:pkill -f "模式" 按命令行模式匹配发信号,killall 进程名 按精确名字——macOS 的 killall 不支持模式,且两个命令在生产服务器上都要先看清会波及谁。
纪律只有一条:先礼后兵。先发 SIGTERM,给进程几秒钟优雅退出的机会;确认它赖着不走,再上 SIGKILL。直接 -9 的代价是:写到一半的文件、没 flush 的缓存、没释放的锁——数据库和队列服务被 -9 杀掉后常常要花额外代价恢复。另外 kill 的是 PID 不是名字,杀之前用 ps 确认那个 PID 真的是你要杀的进程,PID 会被系统复用。
示例
# 系统支持的全部信号
kill -l | tr -s ' ' '
' | sed -n '1,12p'
# 演示 SIGTERM:启动一个进程,礼貌地请它退出
sleep 300 &
PID=$!
echo "启动了进程 $PID"
kill -TERM "$PID"
if wait "$PID" 2>/dev/null; then
echo "进程正常退出"
else
echo "进程已被信号终止(退出码 $?)"
fi
# 演示 SIGKILL:进程没有任何收尾机会,退出码 137 = 128 + 9
sleep 301 &
PID=$!
kill -9 "$PID"
if wait "$PID" 2>/dev/null; then
echo "进程正常退出"
else
echo "进程被强制结束(退出码 $?)"
fi
按名字发信号的命令波及面广,仅作演示:
# 仅示意:按命令行模式批量结束匹配进程(先用 pgrep -f 看会匹配谁)
pkill -f "my-app"
# 仅示意:按精确进程名结束所有同名进程
killall nginx
常见坑
- 上来就 kill -9:不给进程清理机会,可能留下损坏的数据文件和锁。先 TERM,等几秒,再 KILL。
- kill 了认错的 PID:PID 会复用,杀之前 ps -p PID 确认命令行真的是目标进程。
- pkill -f 的模式匹配到自己:pkill -f "deploy" 可能连你的 deploy 脚本一起杀。先 pgrep -f 预演一遍匹配范围。
- 以为 kill 能杀僵尸进程:僵尸已死,信号无处投递,要处理的是它的父进程。
小结
kill 发信号而非只会杀人:TERM 礼貌、KILL 处决、INT 中断、HUP 重载。先礼后兵,杀前确认 PID。下一节看看系统整体信息怎么查。