flock -xn 是最直接有效的解法,需配对使用锁文件路径和-c参数,-n确保非阻塞退出,-c后跟完整命令字符串,锁由内核自动释放,应置于cron入口而非脚本内部。

flock -xn 是最直接有效的解法,但必须配对使用锁文件路径和 -c 参数,且不能忽略 -n 的语义。
为什么 cron 会重复启动脚本
定时任务本身不关心上一次执行是否结束。比如设置 */5 * * * *,而脚本实际运行要 8 分钟,那第 2 次 cron 触发时,第 1 个进程还在跑,就会并行启动第 2 个 —— 这不是 bug,是 cron 的设计逻辑。
常见错误现象包括:
- 日志里出现两组时间戳重叠的输出
-
ps aux | grep your_script.sh显示多个同名进程 - 备份脚本写冲突文件、数据库连接数爆满、磁盘空间被重复占用
flock 命令必须带 -n 和 -c
只加 flock /tmp/lockfile 不起作用;漏掉 -n 会导致新任务卡住等待,反而阻塞后续调度。
正确用法是:
Linux 安全审计工具,检查 SSH 配置、开放/监听端口、防火墙规则(ufw/iptables/nftables)、失败登录尝试、sudoers 权限...
flock -xn /tmp/mybackup.lock -c '/path/to/backup.sh'
关键点:
-
-x表示排他锁(默认可省略),确保同一时刻只有一个进程能拿到锁 -
-n表示非阻塞:拿不到锁就立刻退出,返回状态码 1,cron 不会重试也不会卡住 -
-c后必须跟完整命令字符串,不能写成flock -xn /tmp/l.lock ./a.sh(这会报错或行为异常) - 锁文件路径建议用绝对路径,避免不同用户或 cwd 下指向不同文件
锁文件位置和清理不是问题
很多人担心锁文件残留,其实不用手动清理:
- 进程退出时,flock 持有的文件描述符自动关闭,内核立即释放锁
- 即使脚本被
kill -9强杀,只要没 fork 出长期存活的子进程(如后台 daemon),锁也会释放 - 锁文件本身只是个载体,内容为空也完全 OK;放在
/tmp/或/var/run/都可以,无需特殊权限 - 不要用
flock -u手动解锁 —— 它不是必需的,还可能因时机不对导致竞争
脚本内部加锁不如 cron 外围加锁可靠
有人在脚本开头写 if [ -f /tmp/running ]; then exit; fi; touch /tmp/running,再配 trap 'rm -f /tmp/running' EXIT —— 这种方式有明显缺陷:
- 如果脚本崩溃前没走到
trap注册,锁文件永久残留 - 多个用户或不同 shell 环境下,
$0解析可能出错,dirname $0不一定指向真实路径 - 没有原子性:检查文件存在和创建之间存在竞态窗口
- flock 是内核级的,天然原子,且不依赖脚本自身逻辑健壮性
所以,防重复的防线一定要设在 cron 调用入口,而不是脚本内部。










