摘要:
pkill是 Linux 下基于进程名或正则表达式批量管理进程的高效命令。本文从pkill与kill、killall的区别讲起,覆盖基本用法、-f命令行匹配、按用户/终端过滤、信号控制、pgrep查询搭档、底层实现原理及安全注意事项,帮助你安全高效地管理服务器进程。
用过 Linux 的人大概都经历过这种场景:服务器上跑了一堆同名进程,你想把它们全部杀掉,结果只能ps aux | grep xxx找 PID,然后一个一个kill。效率低不说,还容易漏杀。
pkill就是专门解决这个问题的。它允许你用进程名或正则模式来匹配进程,一条命令就能批量处理。
pkill vs kill vs killall
先理清三者的关系,很多人容易搞混:
| 命令 | 匹配方式 | 典型用法 |
|---|---|---|
kill | PID | kill 1234 |
killall | 进程名(精确匹配) | killall nginx |
pkill | 进程名(正则匹配) | pkill -f "node.*server" |
kill最基础,只能用 PID。killall进了一步,支持进程名,但它是精确匹配,不支持正则。pkill则是最灵活的,底层基于正则表达式引擎,支持模式匹配。
基本用法
最简单的用法——按进程名杀死:
# 杀死所有名为 nginx 的进程pkillnginx# 杀死所有 node 进程pkillnode注意:pkill默认匹配的是进程名的前缀和子串,不是精确匹配。比如pkill ssh会同时匹配sshd、ssh-agent等进程。如果需要精确匹配,加-x参数:
# 只杀死名为 "ssh" 的进程,不影响 sshdpkill-xssh-f 参数:匹配完整命令行
这是pkill最强大的功能。默认情况下,pkill只匹配进程名(通常是可执行文件名),但很多时候你需要匹配命令行参数。
# 杀死所有 node server.js 进程pkill-f"node server.js"# 杀死所有运行在 3000 端口的 node 进程pkill-f"node.*3000"# 杀死所有 python 脚本中包含 crawl 的进程pkill-f"python.*crawl"-f让 pkill 去匹配/proc/<pid>/cmdline中的完整命令行,而不仅仅是进程名。
按用户和终端过滤
# 杀死用户 www 运行的所有 nginx 进程pkill-uwww nginx# 杀死在 pts/0 终端上运行的所有 python 进程pkill-tpts/0 python# 组合使用:杀死用户 deploy 在 pts/1 上的所有进程pkill-udeploy-tpts/1-u支持用户名和 UID,还可以用!取反:
# 杀死所有非 root 用户的 node 进程pkill-u!rootnode信号控制
pkill默认发送SIGTERM(信号 15),这是优雅终止信号。你可以用-signal指定其他信号:
# 强制杀死(SIGKILL,信号 9)pkill-9nginx# 重新加载配置(SIGHUP,信号 1)pkill-HUPnginx# 挂起进程(SIGSTOP)pkill-STOPnode# 恢复进程(SIGCONT)pkill-CONTnode实际工作中,推荐先用SIGTERM,等几秒再SIGKILL:
# 先优雅终止pkill-TERMnginxsleep3# 还没死就强杀pkill-9-xnginxpgrep:pkill 的查询搭档
pgrep和pkill共享同一套匹配逻辑,区别是pgrep只查询不杀进程:
# 查找所有 node 进程的 PIDpgrepnode# 查找并显示进程名pgrep-lnode# 查找并显示完整命令行pgrep-anode# 查找匹配进程的数量pgrep-cnode一个实用的组合:先确认再操作:
# 先看有哪些匹配的进程pgrep-af"python.*worker"# 确认无误后杀死pkill-f"python.*worker"实现原理:pkill 底层做了什么
pkill的核心逻辑其实不复杂,大致流程如下:
1. 读取 /proc 目录下所有数字子目录(每个目录对应一个进程) 2. 对每个进程,读取 /proc/<pid>/stat 获取进程名 3. 如果指定了 -f,额外读取 /proc/<pid>/cmdline 获取完整命令行 4. 用正则表达式匹配进程名或命令行 5. 如果匹配成功,调用 kill(pid, signal) 发送信号用 Python 模拟核心逻辑:
importosimportreimportsignaldefpkill(pattern,full_match=False,sig=signal.SIGTERM):regex=re.compile(pattern)forpid_dirinos.listdir('/proc'):ifnotpid_dir.isdigit():continuepid=int(pid_dir)try:iffull_match:# 读取完整命令行withopen(f'/proc/{pid}/cmdline','rb')asf:cmdline=f.read().replace(b'\x00',b' ').decode('utf-8',errors='ignore')target=cmdlineelse:# 读取进程名(stat 文件的第二个字段)withopen(f'/proc/{pid}/stat')asf:stat=f.read()target=stat.split(')')[0].split('(')[1]ifregex.search(target):os.kill(pid,sig)print(f'Killed{pid}:{target}')except(PermissionError,FileNotFoundError,ProcessLookupError):continue这段代码展示了pkill的本质:遍历/proc、正则匹配、发送信号。
安全注意事项
pkill的正则匹配是一把双刃剑。几个常见坑:
1. 不要用太宽泛的模式
# 危险!会杀死所有包含 "java" 的进程pkilljava# 更安全:精确匹配pkill-xjava# 或更精确的模式pkill-f"java -jar myapp.jar"2. 先用 pgrep 预览
# 养成好习惯:先 pgrep -a 看看会匹配到什么pgrep-af"node"3. 避免误杀自身
pkill不会杀死自己,但可能杀死同名的其他脚本。用-o(最老的)和-n(最新的)可以精确控制:
# 只杀死最老的 node 进程pkill-onode# 只杀死最新的 node 进程pkill-nnode小结
pkill是 Linux 进程管理中非常实用的命令,核心优势在于正则模式匹配和完整命令行匹配(-f)。配合pgrep做预览,可以安全高效地管理服务器上的进程。
更多 Linux 命令参考,可以查看 Linux 命令参考。
相关工具:Linux kill 进程管理命令 | Linux ps 进程监控命令