综合

shell判断进程是否存在

时间:2010-12-5 17:23:32  作者:百科   来源:知识  查看:  评论:0
内容摘要: 写Shell脚本的人,十有八九都遇到过这种场景:脚本里要判断某个进程在不在,不在就拉起来,在就干点别的。这事听着简单,做起来坑不少。最直白的方式是`ps -ef | grep 进程名 | grep

写Shell脚本的断进人,十有八九都遇到过这种场景:脚本里要判断某个进程在不在,程否存不在就拉起来,断进在就干点别的程否存。这事听着简单,断进做起来坑不少。程否存最直白的断进方式是`ps -ef | grep 进程名 | grep -v grep`,然后数行数。程否存但这么写,断进八成会踩到grep自己匹配自己的程否存坑——你明明grep的是进程名,结果grep那个命令行本身也带着这个关键字,断进被一起抓出来了。程否存所以后面必须挂个`grep -v grep`,断进或者用`pgrep`,程否存干净利落。断进

用`pgrep -f 进程名`判断,返回0就是存在,非0就是不存在。这法子比grep管道省事,而且不会误伤。但注意,`pgrep`默认只匹配进程名,不带`-f`的话,它看的是`/proc/pid/comm`,这玩意儿被截断成15个字符,长名字会出问题。比如你有个Java进程叫`order-service-1.0.0.jar`,直接`pgrep -f order-service`没问题,但`pgrep java`可能匹配到一堆无关的JVM。这种模糊匹配的代价,就是误判。

还有一种更隐蔽的坑——僵尸进程。进程死了,但父进程没回收它,`ps`里还能看到,`pgrep`也能抓到。这时候判断“存在”没意义,它已经干不了活了。我写过一次部署脚本,就是被僵尸进程坑了:判断进程存在,跳过启动,结果服务根本没起来,线上挂了十分钟。后来学乖了,判断之前先看状态,`ps -o stat= -p $pid`,如果输出带`Z`,直接当它不存在。

你要是写的是那种需要反复拉起进程的守护脚本,光判断存在不够,还得考虑进程刚启动还没就绪的情况。你拉起一个服务,它要初始化数据库连接,可能要两三秒。这时候脚本下一轮循环来了,`pgrep`一看进程在,跳过启动,但服务其实还没监听端口。稳妥的做法是判断端口,或者判断进程的启动时间是否比脚本上次拉起的时间晚。用`ps -o lstart= -p $pid`拿启动时间,跟当前时间比,差个几秒就当它还没准备好。

还有个细节,进程名带空格或者特殊字符,比如`my app`,`pgrep -f "my app"`没问题,但你要是用`ps -ef | grep "my app"`,管道符和引号处理不好,整条命令就废了。这种时候干脆用`pgrep -f`,省心。不过`-f`匹配的是完整命令行,要是进程的命令行参数里有临时文件路径,每次启动路径不同,那匹配就失效了。所以得想清楚,你到底该按进程名匹配,还是按命令行特征匹配。

最后说一句,别迷信`kill -0 $pid`这招。它能判断进程是否存在,但权限不够时会误报——你连看它的权限都没有,`kill -0`返回失败,你以为是进程没了,其实是权限不足。跑在root下的脚本没这问题,但你要是用普通用户跑,就得小心。我吃过这个亏,后来统一用`pgrep -u $USER`限定用户,才踏实。

判断进程存在这事儿,说到底是跟Linux的进程模型打交道。你得多想一步:进程是不是僵尸、权限够不够、名字会不会被截断、命令行里有没有变量。把这些都考虑进去,脚本才算靠谱。别嫌麻烦,线上出问题的时候,你才知道这些细节值多少钱。

最近更新
热门排行
copyright © 2026 powered by 力不从心网   sitemap