1. pgrep 是什么:一个被低估的进程查询利器
做 Linux 运维这些年,我经常看到同事还在用 ps aux | grep xxx 来查进程,然后再用 awk 把 PID 抠出来。不是说这个方式不能用,而是效率太低,而且坑很多——grep 会把自己匹配进去,还要额外处理管道和文本列。直到后来我习惯用 pgrep,才发现这个命令才是真正为"查进程号"这个高频操作设计的。
pgrep 是 procps 工具集里的一个命令,它的核心作用就是:根据进程名、命令行参数、用户等条件,直接输出符合条件的进程 PID。它不像 ps 那样输出一大屏信息,也不像 grep 那样需要你手动过滤文本流,它的输出就是干干净净的 PID,一个一行。这意味着它天生就是为脚本设计的——你可以直接把 pgrep 的结果赋值给变量,做存活判断、批量信号发送、资源清理等操作。
这篇文章我想从实际场景出发,把 pgrep 的用法、参数、踩坑经验和脚本写法一次讲透。不管你是刚接触 Linux 的新手,还是已经写了好几年 Shell 脚本的运维,这篇文章里应该都有你能直接用上的东西。我会尽量少讲晦涩的理论,多放可复制的命令和案例,你照着敲一遍就会了。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心用法:从最简单的匹配开始
2.1 按进程名精确匹配
pgrep 最简单的用法就是直接跟一个进程名字,比如:
bash复制pgrep nginx
这条命令会在系统进程表里查找进程名里包含"nginx"的进程,并把它们的 PID 按顺序输出。如果你的机器上跑着 Nginx,你会看到类似这样的输出:
bash复制15201
15202
15203
这里有几点需要说明。第一,pgrep 默认是模糊匹配,也就是说只要进程名里包含你要查的字符串,就会被匹配到。比如 pgrep ssh 会同时匹配到 sshd、ssh-agent 这些名字里带"ssh"的进程。如果你只想精确匹配某个名字,需要加 -x 参数:
bash复制pgrep -x nginx
-x 表示 exact match,要求进程名和查询字符串完全一致。这个区别非常关键,特别是在生产环境写脚本时,模糊匹配可能会导致误判。
举个真实的例子。之前我负责的一台服务器上,同时跑着 java 进程和一个名字里包含 java 的监控脚本。有人用 pgrep java 去做进程重启逻辑,结果每次把监控脚本也一同杀了。后来加了 -x 参数,误杀问题才彻底解决。
2.2 用 -f 匹配完整命令行
很多时候,进程的可执行文件名并不能反映它的真实身份。比如你跑了两个 Java 应用,它们的进程名都叫 java,光靠进程名完全区分不开。这时候 -f 参数就派上用场了。
-f 表示匹配完整的命令行参数,而不是只匹配进程名。举个例子:
bash复制pgrep -f "spring-boot-app.jar"
这条命令会去匹配所有完整命令行里包含 spring-boot-app.jar 字符串的进程,不管进程名是不是 java。这在实际工作中非常有用,因为管理多个 Java/Python/Node 应用时,最常见的区分方式就是看启动参数里的 jar 包路径、脚本路径或者配置文件名。
我自己写服务管理脚本时,几乎都会用到 pgrep -f:
bash复制# 检查某个网关服务是否存活
pgrep -f "api-gateway-1.0.0.jar" > /dev/null
if [ $? -eq 0 ]; then
echo "网关服务运行中"
else
echo "网关服务未启动"
fi
注意:
-f匹配的是/proc/<pid>/cmdline里的内容,也就是进程启动时的完整命令行。如果某进程启动后修改了命令行参数(少见但存在),匹配结果可能不准。不过在绝大多数场景下,这个参数非常可靠。
2.3 按用户和归属过滤进程
有时候你只想看某个用户跑的进程,这时候用 -u 参数:
bash复制pgrep -u www
这条命令会列出所有属于 www 用户的进程 PID。-u 后面可以跟用户名,也可以跟 UID,两者都支持。如果你需要排除某个用户的进程,可以用 -v 反向匹配:
bash复制pgrep -u root -v
这条命令会列出所有不属于 root 用户的进程。注意 -v 是全局反向匹配,它会反转整个匹配逻辑,所以使用时要想清楚匹配条件。
另一个跟用户相关的参数是 -U,它表示"真实用户 ID"(real user ID),而 -u 表示"有效用户 ID"(effective user ID)。对于绝大多数普通场景,两者结果是一样的,但在处理设置了 setuid 位的进程时会有差异。日常使用中,直接用 -u 就够了。
2.4 只取最新或最旧的进程:-n 和 -o
如果你启动了多个相同进程,但只想操作其中某一个,可以用 -n 或 -o:
bash复制# 返回最新启动的 nginx 进程
pgrep -n nginx
# 返回最早启动的 nginx 进程
pgrep -o nginx
-n 是 newest,-o 是 oldest。这个功能在滚动发布、灰度更新场景里很实用。比如你有一个多实例的 Java 服务,你想给最新启动的那个实例发信号做测试,直接 pgrep -n -f "app.jar" 就能拿到目标 PID。
需要提一句的是,如果同时加了 -n 和 -o,pgrep 会输出两个 PID:一个是最新的,一个是最旧的。这不是错误,是 pgrep 的设计行为。
2.5 限制匹配数量:-c 和 -d
-c 参数不输出 PID,而是输出匹配到的进程数量。这个在监控场景里非常方便:
bash复制pgrep -c nginx
如果是看数量,也可以用:
bash复制pgrep nginx | wc -l
第一个直接把统计结果输出,第二个先列出 PID 再数行数,效果一样但绕了一圈。我习惯在脚本里直接用 -c,省一步管道。
-d 参数可以指定 PID 之间的分隔符,默认是换行符。如果你想把 PID 一次性传给别的命令,可以用逗号分隔:
bash复制pgrep -d ',' nginx
输出类似:
bash复制15201,15202,15203
这个在配合 kill 命令批量操作时很好用,后面我会具体讲。
3. 深入原理:pgrep 是怎么工作的
3.1 从 /proc 文件系统说起
Linux 系统里有一个虚拟文件系统叫 /proc,它并不存在于磁盘上,而是由内核动态生成的内存镜像。每个进程在 /proc 下都有一个以 PID 命名的目录,比如 PID 为 15201 的进程,就对应 /proc/15201。
pgrep 的底层原理,就是遍历 /proc 下的所有数字目录,逐个读取目录里的相关信息,然后跟你的匹配条件做比对。具体来说:
/proc/<pid>/comm:进程名,通常就是可执行文件名,最多 15 个字符/proc/<pid>/cmdline:进程的完整命令行参数,各参数之间用 null 字符分隔/proc/<pid>/status:包含进程的用户 ID、状态、父进程 ID 等,是一个文本文件
pgrep 默认用 comm 文件来匹配进程名,加了 -f 之后,改用 cmdline 文件来匹配完整命令行。
明白了这个原理,你就能理解为什么 pgrep 默认进程名只能匹配 15 个字符——因为 Linux 内核里 comm 字段的上限就是 15 个字符。一个进程即使实际路径再长,comm 里存的也只是可执行文件的 basename,而且超出 15 个字符的部分会被截断。这一点在生产环境排查问题时很重要,我后面在坑点部分会专门讲。
3.2 与 ps 的区别:pgrep 不会显示进程状态
pgrep 和 ps 最直观的区别是:ps 输出的是一个多维度的表格,包含 PID、TTY、时间、命令、CPU 和内存占用等,而 pgrep 只输出 PID 列表。
这其实不是功能缺失,而是设计取向不同。ps 是给人看的分析工具,pgrep 是给脚本用的搜索工具。你可以在 pgrep 后面再加 -a 参数,让它同时输出 PID 和完整命令行:
bash复制pgrep -a nginx
输出类似:
bash复制15201 /usr/sbin/nginx -g daemon on; master_process on;
15202 /usr/sbin/nginx -g daemon on; master_process on;
加 -a 主要还是为了人在终端核对时方便,真正写脚本时一般用不到,因为脚本只需要 PID。
顺便提一下,ps -C nginx -o pid= 也可以只输出 nginx 的 PID,效果类似。但 ps -C 有几个局限:它只能按进程名匹配,不支持完整命令行匹配,而且某些精简版系统里 ps 的实现(比如 busybox 版本)不支持这个选项。从兼容性和功能性来看,pgrep 都更胜一筹。
3.3 与 pidof 的区别:功能相近但更强大
很多老运维熟悉 pidof 命令,它也能根据进程名查 PID。举个例子:
bash复制pidof nginx
同样输出 nginx 的 PID。那 pgrep 和 pidof 到底有什么区别?
主要区别有三点。第一,pidof 默认不支持正则表达式,只能做精确的名字匹配(实际上是精确比较)。第二,pidof 不支持按用户过滤、不支持按完整命令行匹配,灵活性不如 pgrep。第三,pidof 在某些系统上没有被默认安装,而 pgrep 属于 procps 包,几乎所有主流发行版都自带。
所以我的建议是:优先掌握 pgrep。如果你连 pidof 都记不全,干脆就只记 pgrep,它覆盖了 pidof 的绝大多数使用场景。
4. 高级参数与正则匹配
4.1 正则表达式的应用
pgrep 默认支持扩展正则表达式(Extended Regular Expression)。这意味着你可以用管道符、方括号、量词等正则语法来构建复杂的匹配模式。
看几个例子:
bash复制# 匹配 java 或 python 进程
pgrep "java|python"
# 匹配以 ssh 开头的进程
pgrep "^ssh"
# 匹配名字为 nginx 或 nginx-worker 的进程
pgrep "nginx(-worker)?"
用正则表达式时有个容易踩的坑:如果你在终端里直接运行,管道符 | 会被 Shell 解释为管道操作。所以要么用引号把正则表达式包起来,要么转义管道符。我强烈建议任何时候都用引号包起来,这是一个好习惯。
举例说明:
bash复制# 错误写法:管道符被 Shell 解释
pgrep java|python
# 正确写法:引号包裹正则
pgrep "java|python"
第一个写法实际执行的是 pgrep java,然后输出被管道给 python 命令,结果完全不是你想的那样。这种错误在刚接触正则的用户身上非常常见,务必注意。
4.2 常用配套参数速查
pgrep 的参数虽然多,但实际高频使用的就那么几个。我把常用参数整理成了一个表格,方便查阅:
| 参数 | 含义 | 适用场景 |
|---|---|---|
-x |
精确匹配进程名 | 避免模糊匹配误伤同名进程 |
-f |
匹配完整命令行 | 区分不同 jar 包、脚本路径 |
-u |
按有效用户过滤 | 查看某用户的全部进程 |
-U |
按真实用户过滤 | 处理 setuid 进程时区分真实身份 |
-n |
取最新启动的进程 | 灰度发布、滚动更新时定位最新实例 |
-o |
取最早启动的进程 | 定位最老实例 |
-c |
输出匹配数量 | 监控脚本中的非零判断 |
-d |
自定义输出分隔符 | 批量拼接 PID 传给 kill 等命令 |
-a |
同时输出 PID 和命令行 | 人工核对的场景 |
-v |
反向匹配 | 排除指定用户的进程 |
-P |
按父进程 PID 过滤 | 找到某个父进程的所有子进程 |
-L |
按运行级别过滤 | 查看特定运行级别启动的进程 |
-l |
同时输出进程名和 PID | 快速确认匹配结果 |
这里我想特别提一下 -P 参数。你需要先知道父进程的 PID,然后再用它查所有子进程:
bash复制pgrep -P 15201
这条命令会列出 PID 为 15201 的进程的所有子进程 PID。写服务管理脚本时,如果你知道主进程 PID,可以用这个参数把所有子进程找出来一起操作,非常实用。
4.3 参数组合的实际场景
真正用 pgrep 的时候,很难只用一个参数解决所有需求,大多数时候是组合使用。我最常用的一组组合是:
bash复制# 查看 www 用户下,命令行里含 api-gateway 的进程
pgrep -a -u www -f "api-gateway"
还有一个我几乎天天用的场景:配合 pkill 做精确停止服务。pkill 和 pgrep 是同门兄弟,匹配条件完全一样,但 pkill 是对匹配到的进程发信号。我喜欢先用 pgrep 确认要杀哪些进程,再用 pkill 执行,每一步都能看到实际影响范围,避免误杀。
bash复制# 第一步:查看将匹配哪些进程
pgrep -a -f "old-service.jar"
# 第二步:确认无误后,用 pkill 发 TERM 信号
pkill -f "old-service.jar"
这种"先看后杀"的习惯,我强烈建议每个人都养成。在自动化脚本里,pkill 确实方便,但如果你连 pgrep 查出来的结果都没看过一遍就直接杀,那就是在赌自己的匹配条件没有写错。在线上环境,一次误杀可能意味着一次事故。
5. 真实场景实战:从存活判断到自动化运维
5.1 服务存活检测脚本
写一个简单的服务保活脚本,是学习 pgrep 最经典的入门练习。先看一个最基本的版本:
bash复制#!/bin/bash
SERVICE_PATTERN="myapp.jar"
if pgrep -f "$SERVICE_PATTERN" > /dev/null; then
echo "服务运行中,无需处理"
else
echo "服务已停止,准备启动..."
nohup java -jar /opt/app/myapp.jar > /var/log/myapp.log 2>&1 &
fi
这个地方有几个关键细节值得展开说。
第一,pgrep 如果匹配到了进程,返回状态码是 0;如果没有匹配到,返回状态码是 1。Shell 里的 if 直接根据返回值判断,所以不需要额外写比较语句。第二,我把输出重定向到了 /dev/null,因为脚本只需要状态码,不需要 PID 列表。第三,用了 -f 而不是默认进程名匹配,原因之前说过:Java 进程的可执行文件都叫 java,只有完整命令行里才能区分具体是哪个应用。
如果你想把这个脚本做得更健壮,还需要考虑一个问题:那就是刚启动的进程可能还没来得及写 cmdline 就被 pgrep 查到了,或者更常见的情况——进程挂起但还在进程表里。这种"僵尸进程"用 pgrep 是能查到的,但业务上它已经不提供服务了。
所以更严谨的存活检测,应该配合端口检测或 HTTP 探测。比如用 curl 检查服务端口是否响应:
bash复制#!/bin/bash
SERVICE_PATTERN="myapp.jar"
HEALTH_URL="http://127.0.0.1:8080/health"
# 第二步:检查进程是否存在
if ! pgrep -f "$SERVICE_PATTERN" > /dev/null; then
echo "进程不存在,执行启动"
nohup java -jar /opt/app/myapp.jar > /var/log/myapp.log 2>&1 &
exit 0
fi
# 第二步:检查端口是否可访问
if curl -s -f "$HEALTH_URL" > /dev/null 2>&1; then
echo "服务健康"
else
echo "进程存在但端口无响应,尝试重启"
pkill -f "$SERVICE_PATTERN"
sleep 3
nohup java -jar /opt/app/myapp.jar > /var/log/myapp.log 2>&1 &
fi
生产环境的保活脚本,双检查是一个很好的实践。只看进程存在与否,只能说明进程还在跑,不能说明服务是健康的。我经历过不止一次进程活着但端口卡死的情况,如果脚本只做进程检查,它永远不会触发重启逻辑。
5.2 批量操作:优雅停服与滚动重启
pgrep 的另一个高频场景是批量操作进程。比如你要停掉某个服务的所有实例,可以这样:
bash复制# 用 pgrep 拿到所有实例 PID,逐个发送 TERM 信号
pgrep -f "myapp.jar" | xargs -r kill
# 等待 5 秒,如果还有残留进程,强制 KILL
sleep 5
pgrep -f "myapp.jar" | xargs -r kill -9
这里用了 xargs -r,-r 的作用是:如果前面的输出为空,就不执行后面的命令。这个细节很实用,能避免"没有匹配到进程时执行 kill 直接报错"的问题。
如果不想用管道加 xargs,pkill 提供了更方便的写法:
bash复制pkill -f "myapp.jar"
pkill 默认和 kill 一样,发的是 TERM 信号(信号值 15),给进程一个优雅退出的机会。如果进程不响应,再补一个 KILL(信号值 9):
bash复制pkill -9 -f "myapp.jar"
顺带说一下,有些脚本里会看到用 kill $(pgrep -f xxx) 的写法,这个在匹配结果为空时,命令会变成 kill 不带参数,直接报错。所以用 xargs -r 或者 pkill 会安全得多。
处理完停止,再看滚动重启。假设你有四个 Nginx worker 进程,想一个一个地重启,可以用 pgrep -n 结合循环:
bash复制# 每次只处理最新启动的那个进程
for i in 1 2 3 4; do
PID=$(pgrep -n nginx)
if [ -n "$PID" ]; then
kill "$PID"
sleep 2
fi
done
这个写法可以确保同一时间只杀掉一个进程,其余进程继续承担流量,适用于对可用性要求比较高的场景。循环的次数不一定非要写死,可以根据 pgrep -c 拿到的数量动态决定。
5.3 资源清理与日志轮转
在写日志清理脚本时,pgrep 也经常被拿来配合使用。比如有些应用写日志前会持有文件句柄,如果你直接删除日志文件,进程仍然会往已删除的 inode 里写数据,磁盘空间并不会被释放。要解决这个问题,通常需要向进程发送信号,让它重新打开日志文件。
一个经典的做法是:
bash复制# 日志轮转前,找到主进程 PID
MASTER_PID=$(pgrep -f "myapp-master")
# 执行日志切割
logrotate -f /etc/logrotate.d/myapp
# 向进程发送 USR1 信号,让应用重新打开日志句柄
kill -USR1 "$MASTER_PID"
这套逻辑里,pgrep 承担的角色是动态获取 PID。如果进程 PID 可能变化,脚本里写死任何 PID 都是不可靠的,用 pgrep 动态获取是更稳妥的方案。
6. 常见坑点与排查技巧
6.1 第一个坑:pgrep 匹配到自己的脚本进程
这是新手最容易遇到的问题。假设你写了一个脚本叫 check_nginx.sh,文件内容里有这样一行:
bash复制pgrep -f "nginx"
这个脚本在运行时,它自身的进程也是一个命令行包含 nginx 的进程——因为它的命令行就是 bash check_nginx.sh,而这个脚本内容的执行并没有直接影响命令行。等等,这里容易混淆。我详细解释一下。
pgrep -f "nginx" 匹配的是 /proc/<pid>/cmdline,脚本自己的命令行是 bash check_nginx.sh,这个字符串里并不包含"nginx",所以脚本自身不会被匹配。真正会被匹配的是下面这种情况:
bash复制./check_nginx.sh # 脚本文件名本身叫 check_nginx.sh,不含 nginx
那什么情况下会匹配到脚本自身?当你的匹配模式跟脚本名的某一部分重合时。比如脚本叫 nginx_check.sh,你在脚本里跑了 pgrep -f "nginx",那这个脚本进程自身就符合匹配条件,因为它的命令行里包含 nginx 字样。
实际环境中更常见的例子是:
bash复制# 脚本名为 stop_app.sh,里面执行了
pkill -f "app.jar"
这个脚本自身不会匹配到,但如果启动脚本的命令是 sh stop_app.sh,也不会匹配。问题出在另一个场景:当你用一个父 shell 去执行一串包含匹配关键字的命令时,那个父 shell 也会被匹配到。
比如你在终端里直接运行:
bash复制pgrep -f "nginx"
如果这个终端是通过 SSH 连接的,而且 SSH 的命令行参数里恰好包含 nginx 字样,这种极端情况确实会被匹配到。但更常见的是 cron 任务或 CI 任务里,整条任务命令被 shell 包了一层,命令行的完整字符串包含了你要匹配的特征。
怎么规避? 我的建议是:匹配条件尽量精确,加上 -x 或更独特的字符串;或者在使用 pkill 之前,先跑一次 pgrep -a 看看实际匹配了哪些进程。如果在脚本里,还可以用 $$ 来排除自身 PID:
bash复制for PID in $(pgrep -f "app.jar"); do
if [ "$PID" != "$$" ]; then
kill "$PID"
fi
done
6.2 第二个坑:进程名被截断到 15 个字符
之前提到过 Linux 内核的 comm 字段只有 15 个字符的容量,这里展开讲讲它的影响。如果你用进程名匹配(不加 -f),实际上比对的是 /proc/<pid>/comm 的前 15 个字符。
比如一个可执行文件叫 my-very-long-service-name,15 个字符之后的部分会被截断。你运行 pgrep my-very-long-service-name,正常情况下能匹配到,但如果有个同名文件的不同版本截断后恰好相同,就会出问题。
怎么确认你匹配到的是不是同一进程?很简单,用 -a 把命令行打出来看:
bash复制pgrep -a -f "my-very-long-service-name"
我建议在涉及长文件名进程的脚本里,直接统一用 -f 匹配完整命令行,不要依赖默认的进程名匹配。这样能完全绕开 15 字符截断的问题。
6.3 第三个坑:权限不足导致看不到某些进程
Linux 的 /proc 文件系统对进程信息的可读性有权限限制。普通用户运行 pgrep 时,默认能看到所有进程的 PID,但如果你加 -a 查看命令行,有些进程的信息可能看不到。
具体来说,普通用户查看其他用户的进程时,/proc/<pid>/cmdline 文件是否能读取,取决于内核的 fs.suid_dumpable 和 hidepid 等参数。在某些系统上(比如挂载 /proc 时用了 hidepid=2),普通用户只能看到自己进程的信息,连 PID 都看不到。
排查这类问题时,先检查 /proc 的挂载选项:
bash复制mount | grep /proc
如果确实存在权限限制,而你确实有 sudo 权限,可以在需要时用 sudo pgrep ... 来查看;但要注意,在脚本里随意使用 sudo 不是好习惯,最好通过配置让脚本以合适的用户运行。
另外提一个和权限相关的点:pgrep -u 查不到某个用户的进程,不一定是权限问题,也可能是这个用户的密码有效期设置导致部分进程无法正常启动。这些属于系统层面的其他问题,需要单独排查。
6.4 第四个坑:pgrep 返回码与管道组合的陷阱
当你把 pgrep 和管道一起使用时,Shell 的管道机制会让最终返回码变成最后一个命令的返回码,而不是 pgrep 本身的。这是一个很容易被忽略的行为。
举个例子:
bash复制pgrep nginx | grep -q . && echo "找到了" || echo "没找到"
如果 nginx 进程存在,pgrep nginx 输出一堆 PID,grep -q . 成功返回 0,打印"找到了",这个没问题。但如果 nginx 进程不存在,pgrep 的输出为空,grep -q . 因没有输入而失败返回 1,打印"没找到",逻辑也说得通。
但如果你的管道后面跟的不是这种可以配合的命令,而是类似 wc -l,那 wc 永远返回 0,不管前面有没有进程。所以如果你要判断进程是否存在,最可靠的方式是直接用 pgrep 的返回码:
bash复制if pgrep nginx > /dev/null; then
echo "找到了"
fi
在脚本里,尽量避免 pgrep 和管道组合后依赖整体返回码来判定结果。这是很多 Shell 脚本 Bug 的来源。
7. 脚本写作的实用技巧补充
7.1 写好日志,方便事后排查
在自动化运维脚本里,pgrep 结果最好都打日志,特别是生产环境的保活或清理脚本。比如:
bash复制LOG_FILE="/var/log/myapp-monitor.log"
if pgrep -f "myapp.jar" > /dev/null; then
echo "$(date '+%Y-%m-%d %H:%M:%S') 服务正常运行" >> "$LOG_FILE"
else
echo "$(date '+%Y-%m-%d %H:%M:%S') 服务异常,尝试重启" >> "$LOG_FILE"
# 启动逻辑...
fi
日志里带上时间戳,事后追溯问题时能省很多时间。不要觉得多写几行日志是废话,出故障时日志就是你的第一手证据。
7.2 使用 pgrep 时注意 Shell 的选项差异
不同发行版里的 pgrep 其实不一定完全相同。大部分 Linux 发行版用的是 procps-ng 版本的 pgrep,选项丰富、行为统一。但某些精简版系统(比如嵌入式环境的 busybox)里的 pgrep 功能会大打折扣,可能连 -f 都不支持。
写跨平台脚本前,先确认目标系统里 pgrep 是哪个实现:
bash复制which pgrep
pgrep --version
如果是 busybox 版本,尽量只用最基本的匹配方式;条件允许的话,建议在系统里补装一个完整的 procps 工具集,省得到处是兼容性问题。
8. 一点个人体会
用 pgrep 这个命令已经好几年了,说实话它算不上什么高深的技术,但真正把它用得顺手之后,写脚本的效率和正确率都提升了不少。我以前也用 ps aux | grep xxx 加 awk '{print $2}' 查 PID,但总觉得别扭:管道一长,出错概率就高,还要处理 grep 匹配到自身的问题。换 pgrep 之后,写脚本干净多了,人也不用在终端前盯着一大屏输出找 PID。
如果让我给刚接触 Linux 的朋友一个建议,那就是别急着记一大堆命令,先把 pgrep、pkill、ps、kill 这几个进程管理命令的组合拳练熟。进程管理是所有 Linux 操作的底座,而 pgrep 又是进程管理里最高频的一环。这篇文章里提到的参数和脚本,你可以在自己的机器上逐个试验,有条件的话故意构造一些"坑"(比如匹配自身、匹配空结果),看看输出和返回码是什么样。把这些边界情况亲手摸一遍,比背十遍命令帮助文档都管用。
