Linux定时任务防重复执行的核心是避免并发导致的资源冲突,常用方法包括:用pgrep检查进程、flock文件锁、mkdir原子锁及时间戳逻辑判重。

Linux 中定时任务本身不会“重复添加”,真正需要判断的是:同一任务是否已在运行中,或是否已由其他实例触发。crond 只负责按时间表拉起新进程,不检查前序任务状态。所以所谓“重复添加”的实质,是任务并发执行导致资源冲突、数据错乱或重复操作。
检查当前任务进程是否存在
最直接的方式是用 ps 或 pgrep 查找正在运行的同名脚本或命令:
- pgrep -f "backup.sh" —— 匹配完整命令行,适合带参数的脚本
- ps aux | grep "[b]ackup.sh" —— 方括号避免匹配 grep 自身
- 在脚本开头加:if pgrep -f "$0" | grep -v $$ > /dev/null; then exit 0; fi,自动跳过重复启动
用 flock 做轻量级单机互斥
flock 是最常用、最稳妥的本地防重入手段,依赖文件锁的原子性:
- 在 crontab 中写:* * * * * flock -n /tmp/backup.lock -c "/path/to/backup.sh"
- -n 表示非阻塞,获取不到锁就立即退出,不会排队等待
- 锁文件路径必须固定且可写(推荐 /tmp/ 或 /var/run/),避免 NFS 等不支持 flock 的文件系统
用 mkdir 实现原子性锁(幂等首选)
mkdir 具有天然原子性:成功即获得锁,失败说明已被占用。比 flock 更可靠,尤其适合需要记录状态的场景:
- 脚本开头加入:LOCK_DIR="/tmp/backup.lock"; if ! mkdir "$LOCK_DIR" 2>/dev/null; then echo "Already running"; exit 0; fi
- 结尾务必清理:rm -rf "$LOCK_DIR"(建议用 trap 保证异常退出也释放)
- 该方式还能自然携带元信息,比如在 lock 目录下写入 PID、开始时间、主机名,便于排查
结合日志与时间戳做逻辑判重
对周期性任务(如每小时备份),可不依赖进程锁,改用“上次执行时间”判断:
- 每次成功执行后,写一个时间戳文件:date +%s > /var/run/backup.last
- 脚本开头读取:LAST=$(cat /var/run/backup.last 2>/dev/null || echo 0)
- 若 $(date +%s) - $LAST < 3600,说明一小时内已跑过,直接退出
- 适合任务执行时间短、但调度间隔更短的场景(如每5分钟检查,实际只需每小时生效一次)


















