You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bash脚本检测进程运行状态、cron执行异常及flock报错排查

Bash单实例脚本问题排查与实现方案

各方案失效原因

  • pgrep方案异常原因:cron调度脚本时,会先启动一个shell进程加载执行脚本,该父进程的命令行同样包含脚本路径,pgrep -f $0会同时匹配到父shell进程、当前脚本进程两个PID,和SSH手动执行时的进程结构不一致,因此返回两个PID导致判断失效,才会出现14767 14770 . != . 14770的输出。
  • ps统计方案异常原因:存在两个语法和逻辑错误:第一,判断逻辑写混,[ -n "$(...)" ]是判断字符串非空,单中括号内的>是文件重定向符而非数值比较符,根本不会执行数值大小判断;第二,脚本内执行管道命令时,会生成包含脚本名的子进程,哪怕加了grep -v grep,统计到的进程数也会比手动执行时多1,阈值判断完全失准,因此始终触发"already running"提示。
  • flock方案报错原因:cron默认的PATH环境变量不包含脚本所在目录,若cron任务里写的是相对路径调用脚本,$0拿到的是不带完整路径的脚本名,flock无法定位到脚本文件,就会抛出flock: failed to execute run.sh: No such file or directory错误。

可靠的单实例实现方案

方案1:flock实现(推荐,无逻辑漏洞)

该方案依赖系统自带的flock文件锁工具,不需要手动匹配进程,不会出现误判:

#!/bin/bash
# 提前获取脚本绝对路径,解决cron下相对路径找不到文件的问题
SCRIPT_ABSPATH=$(readlink -f "$0")
# 独立锁文件路径,避免锁脚本本身带来的权限问题
LOCK_FILE="/var/run/$(basename "$0").lock"

# 绑定文件描述符到锁文件,非阻塞申请锁
exec 9>"$LOCK_FILE"
if ! flock -n 9; then
    echo "Task is already running, exit now."
    exit 1
fi

# 以下为正常业务逻辑
echo "Script started, PID: $$"
# 实际业务命令写在这里

关键说明:

  • 用readlink -f提前解析脚本绝对路径,彻底规避cron下相对路径的问题
  • 单独创建锁文件而非直接锁定脚本自身,避免脚本无执行权限、目录只读导致的异常
  • flock -n为非阻塞模式,拿不到锁直接退出,不会卡住等待上一个任务执行
  • 脚本退出时操作系统会自动释放文件锁,不需要手动清理锁文件

方案2:PID文件实现(无flock依赖时使用)

若系统未预装flock,可使用PID文件方案,需要额外处理异常退出残留的PID文件:

#!/bin/bash
PID_FILE="/var/run/$(basename "$0").pid"

# 校验已存在的PID文件
if [ -f "$PID_FILE" ]; then
    OLD_PID=$(cat "$PID_FILE")
    # 发送空信号校验旧进程是否真实存在,避免残留PID文件导致误判
    if kill -0 "$OLD_PID" 2>/dev/null; then
        echo "Task is already running, PID: $OLD_PID, exit now."
        exit 1
    else
        # 清理无效残留PID文件
        rm -f "$PID_FILE"
    fi
fi

# 写入当前进程PID,脚本退出时自动清理PID文件
echo $$ > "$PID_FILE"
trap "rm -f $PID_FILE" EXIT

# 以下为正常业务逻辑
echo "Script started, PID: $$"
# 实际业务命令写在这里

内容的提问来源于stack exchange,提问作者Andrew Newby

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 23:21:44