在 Linux 中,终止或控制一个进程并不是直接“杀死”它,而是通过向目标进程发送信号(signal)来实现。信号是内核提供的一种进程间异步通知机制,用来告诉进程“发生了某件事”,比如用户按下了 Ctrl+C、子进程结束、定时器到期等。kill 和 killall 是用于手动发送信号的两个最常用命令,它们的名字容易让人误以为只能用来终止进程,实际上功能要丰富得多。
1. kill:向指定进程 ID 发送信号
最基本的 kill 命令格式是 kill [信号] PID,例如:
kill 1234 # 默认发送 TERM(终止)信号
kill -9 1234 # 发送 KILL 信号,强制杀死
kill -HUP 1234 # 发送 HUP 信号,常用于重新加载配置
这里的 PID 是进程的唯一标识,可以用 ps、top 或 pidof 等命令获取。
常用信号及其含义:
- TERM (15):默认信号,请求进程正常退出。程序可以捕获这个信号,在退出前执行清理工作(如关闭文件、保存状态)。
- KILL (9):强制杀死进程,内核会立即终止它,程序无法捕获或忽略。只有在进程卡死、不响应 TERM 时才应使用,因为它让程序来不及善后。
- HUP (1):最初设计是终端挂断信号,现在最常用于让守护进程重新读取配置文件而无需重启。
- INT (2):相当于在终端按下 Ctrl+C,通常中断前台进程。
- STOP (19) 和 CONT (18):暂停和恢复进程,可用于任务控制。
信号可以用数字或名字指定,例如 kill -15 等同于 kill -TERM。kill -l 可以列出所有信号。
2. killall:按进程名发送信号
killall 不需要知道 PID,直接按程序的名字发送信号。例如:
killall nginx # 向所有名为 nginx 的进程发送 TERM
killall -9 java # 强制杀死所有 java 进程(谨慎使用)
killall -HUP sshd # 让 sshd 重新加载配置
它的语法与 kill 一致,只是参数从 PID 换成了进程名。需要注意:
- 默认会匹配所有同名的进程实例,比如
killall chrome会杀掉所有正在运行的 chrome 窗口。 - 可以使用
-u指定用户,killall -u zhangsan firefox仅终止属于zhangsan的 firefox 进程。 - 对于精确匹配,
killall要求完整的进程名(如nginx而非ng),但有些实现支持-e或--exact选项。 - 在 Solaris 等系统上
killall行为不同(会杀掉所有进程),但 Linux 版本是安全的。
3. 何时使用 kill,何时使用 killall
- kill:当你知道具体 PID 时(比如从日志中抓取、通过
pidof查询),或者需要精确操作单个进程时。 - killall:当你只知道进程名字但懒得查找 PID 时,或者想一次性向多个同名进程发送信号时(比如批量重启所有 worker 进程)。
4. 实用建议
- 尽可能先使用
TERM(默认)或HUP,给进程一个妥善退出的机会,避免数据丢失或留下锁文件。 - 只有在进程已经无响应、
TERM无效时才使用KILL。发出KILL后进程立即消失,不会有任何提示。 - 在杀死前可以用
pgrep 进程名或pidof 进程名预览将被影响的 PID,避免误杀。 - 如果进程是 systemd 等服务管理器管理的,优先使用
systemctl stop 服务名,因为这些管理器会正确地发送信号并跟踪状态。
5. 综合示例
假设 Nginx 服务日志不正常,需要重新加载配置,而某个僵死的 Java 进程必须强制终止:
# 平滑重启 nginx(重新打开日志文件)
killall -USR1 nginx
# 强制终止一个卡死的 java 进程(假设 PID 为 9876)
kill -9 9876
# 让 crond 服务重新读取 crontab 文件
kill -HUP $(pidof crond)
这些命令简单直接,但功能强大,是日常管理和排错中不可或缺的基础技能。