Ubuntu 20.04 cron执行shell脚本ps进程计数与手动执行结果不符
cron执行脚本时ps进程计数与手动执行不一致问题排查
核心原因
差异本质是ps -efa | grep -v grep | grep import -c的匹配逻辑存在缺陷:该命令会对全量进程的完整命令行做模糊匹配,只要命令行中包含import字符串就会被统计,grep -v grep仅能排除grep命令自身的进程,无法排除其他路径、参数中带import的关联进程;而cron调度的执行环境和交互式手动执行的环境中,这类附带的带import关键字的进程数量不一致,最终导致计数差。
两种场景下的计数构成
- 手动执行脚本场景
交互式终端下执行脚本时,除目标Java进程外,几乎没有其他命令行带import的进程:- Java进程存活时:仅匹配到1个目标Java服务进程,val=1
- Java进程停止时:无匹配进程,val=0
和观测到的现象完全一致。
- cron自动调度场景
cron执行定时任务时,会生成一整条任务调度链路的进程,这些进程的命令行中都包含脚本路径/software/deployment/service/import2/restart_import.sh,路径本身带有import字符串,会被grep命中,这部分进程固定占3个匹配项:- cron服务fork出的执行定时任务的shell父进程
- 执行
ps命令、管道命令时生成的子shell进程 - 脚本执行过程中产生的其他关联临时子进程
在此基础上叠加目标Java进程的计数:
- Java进程存活时:3个固定关联进程 + 1个Java进程 = 4,val=4
- Java进程停止时:仅剩余3个固定关联进程,val=3
修复方案
原逻辑写死判断val -eq 4可靠性极差,只要cron执行链路的进程数随系统配置、版本变化发生变动,判断就会失效,建议替换为精确匹配目标Java进程特征的判断逻辑,两种常用实现如下:
- 用
pgrep精确匹配进程特征(推荐)
替换原有的进程计数行:
# 仅匹配启动了指定war包的Java进程,自动排除脚本、cron链路进程干扰 val=$(pgrep -f "java.*import-web-1.0-SNAPSHOT.war" -c)
同时将判断逻辑修改为:
if [[ ${val} -ge 1 ]]; then echo "Import Up" >> /tmp/output.log else # 原有拉起逻辑保持不变 fi
该写法在手动执行、cron执行环境下计数一致,Java进程存活时val=1,停止时val=0,不会出现误判。
2. 优化原有grep匹配规则
如果不想依赖pgrep,可以收窄grep的匹配范围,同时排除脚本自身进程:
val=$(ps -efa | grep -v grep | grep -v restart_import.sh | grep "java.*import-web-1.0-SNAPSHOT.war" -c)
该写法通过额外的grep -v restart_import.sh排除脚本自身进程,同时将匹配关键字从宽泛的import替换为Java进程独有的war包名称,避免匹配到无关进程。
内容的提问来源于stack exchange,提问作者Amit Dube
相关产品推荐
相关产品推荐

