Linux pkill 命令:按模式批量杀死进程的原理与实践

0 阅读4分钟

摘要pkill 是 Linux 下基于进程名或正则表达式批量管理进程的高效命令。本文从 pkillkillkillall 的区别讲起,覆盖基本用法、-f 命令行匹配、按用户/终端过滤、信号控制、pgrep 查询搭档、底层实现原理及安全注意事项,帮助你安全高效地管理服务器进程。

用过 Linux 的人大概都经历过这种场景:服务器上跑了一堆同名进程,你想把它们全部杀掉,结果只能 ps aux | grep xxx 找 PID,然后一个一个 kill。效率低不说,还容易漏杀。

pkill 就是专门解决这个问题的。它允许你用进程名正则模式来匹配进程,一条命令就能批量处理。

pkill vs kill vs killall

先理清三者的关系,很多人容易搞混:

命令匹配方式典型用法
killPIDkill 1234
killall进程名(精确匹配)killall nginx
pkill进程名(正则匹配)pkill -f "node.*server"

kill 最基础,只能用 PID。killall 进了一步,支持进程名,但它是精确匹配,不支持正则。pkill 则是最灵活的,底层基于 正则表达式 引擎,支持模式匹配。

基本用法

最简单的用法——按进程名杀死:

# 杀死所有名为 nginx 的进程
pkill nginx

# 杀死所有 node 进程
pkill node

注意:pkill 默认匹配的是进程名的前缀和子串,不是精确匹配。比如 pkill ssh 会同时匹配 sshdssh-agent 等进程。如果需要精确匹配,加 -x 参数:

# 只杀死名为 "ssh" 的进程,不影响 sshd
pkill -x ssh

-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 -u www nginx

# 杀死在 pts/0 终端上运行的所有 python 进程
pkill -t pts/0 python

# 组合使用:杀死用户 deploy 在 pts/1 上的所有进程
pkill -u deploy -t pts/1

-u 支持用户名和 UID,还可以用 ! 取反:

# 杀死所有非 root 用户的 node 进程
pkill -u !root node

信号 控制

pkill 默认发送 SIGTERM(信号 15),这是优雅终止信号。你可以用 -signal 指定其他信号:

# 强制杀死(SIGKILL,信号 9)
pkill -9 nginx

# 重新加载配置(SIGHUP,信号 1)
pkill -HUP nginx

# 挂起进程(SIGSTOP)
pkill -STOP node

# 恢复进程(SIGCONT)
pkill -CONT node

实际工作中,推荐先用 SIGTERM,等几秒再 SIGKILL

# 先优雅终止
pkill -TERM nginx
sleep 3
# 还没死就强杀
pkill -9 -x nginx

pgrep:pkill 的查询搭档

pgreppkill 共享同一套匹配逻辑,区别是 pgrep 只查询不杀进程:

# 查找所有 node 进程的 PID
pgrep node

# 查找并显示进程名
pgrep -l node

# 查找并显示完整命令行
pgrep -a node

# 查找匹配进程的数量
pgrep -c node

一个实用的组合:先确认再操作:

# 先看有哪些匹配的进程
pgrep -af "python.*worker"
# 确认无误后杀死
pkill -f "python.*worker"

实现原理:pkill 底层做了什么

pkill 的核心逻辑其实不复杂,大致流程如下:

用 Python 模拟核心逻辑:

import os
import re
import signal

def pkill(pattern, full_match=False, sig=signal.SIGTERM):
    regex = re.compile(pattern)
    for pid_dir in os.listdir('/proc'):
        if not pid_dir.isdigit():
            continue
        pid = int(pid_dir)
        try:
            if full_match:
                # 读取完整命令行
                with open(f'/proc/{pid}/cmdline', 'rb') as f:
                    cmdline = f.read().replace(b'\x00', b' ').decode('utf-8', errors='ignore')
                target = cmdline
            else:
                # 读取进程名(stat 文件的第二个字段)
                with open(f'/proc/{pid}/stat') as f:
                    stat = f.read()
                target = stat.split(')')[0].split('(')[1]
            if regex.search(target):
                os.kill(pid, sig)
                print(f'Killed {pid}: {target}')
        except (PermissionError, FileNotFoundError, ProcessLookupError):
            continue

这段代码展示了 pkill 的本质:遍历 /proc、正则匹配、发送信号

安全注意事项

pkill 的正则匹配是一把双刃剑。几个常见坑:

1. 不要用太宽泛的模式

# 危险!会杀死所有包含 "java" 的进程
pkill java

# 更安全:精确匹配
pkill -x java
# 或更精确的模式
pkill -f "java -jar myapp.jar"

2. 先用 pgrep 预览

# 养成好习惯:先 pgrep -a 看看会匹配到什么
pgrep -af "node"

3. 避免误杀自身

pkill 不会杀死自己,但可能杀死同名的其他脚本。用 -o(最老的)和 -n(最新的)可以精确控制:

# 只杀死最老的 node 进程
pkill -o node

# 只杀死最新的 node 进程
pkill -n node

小结

pkill 是 Linux 进程管理中非常实用的命令,核心优势在于正则模式匹配完整命令行匹配-f)。配合 pgrep 做预览,可以安全高效地管理服务器上的进程。

更多 Linux 命令参考,可以查看 Linux 命令参考


相关工具:Linux kill 进程管理命令 | Linux ps 进程监控命令在这里插入图片描述