flock实现脚本互斥需所有参与方主动调用,锁的是文件描述符而非路径,推荐用独立锁文件避免权限问题;-n立即退出,-w等待超时退出;exec配合fd加锁最灵活;多脚本共用锁时须路径一致、类型统一、不手动删锁文件。

直接用 flock 就能实现脚本互斥,不需要改代码逻辑、不依赖外部服务,但必须理解它只做「建议性锁」——所有参与方都得主动调用 flock 才有效。
为什么flock -x /path/to/file会失败或没效果
常见错误是直接对目标文件加锁(比如 flock -x /etc/config.json),但该文件可能没写权限,或者被其他进程以只读方式打开导致锁不生效。更糟的是,有些程序根本不检查锁,直接覆盖写入。
-
flock锁的是「打开的文件描述符」,不是文件路径本身;路径只是用来获取 fd 的入口 - 若目标文件权限不足(如 root 写、普通用户只读),
flock -x会报Permission denied - 推荐用独立锁文件(如
/tmp/myapp.lock),避免和业务文件权限耦合 - 锁文件本身只需可创建+可写,无需特殊内容,甚至可以是空文件
flock -n 和 flock -w 的实际区别
-n 是“试一下,不行立刻退出”,-w 是“最多等 N 秒,超时也退出”。两者都避免无限阻塞,但行为不同。
-
flock -n /tmp/app.lock -c './do_something.sh':如果锁被占,命令根本不执行,返回非零退出码(如 1) -
flock -w 5 /tmp/app.lock -c './do_something.sh':最多等 5 秒,期间锁释放了就立即执行;超时则退出并返回 1 - 在 crontab 中优先用
-n,防止任务堆积;在关键流程中可用-w给一点缓冲时间 - 注意:
-w的单位是秒,不支持小数;且 timeout 到达后,flock进程自身退出,不会 kill 已启动的子命令
bash 脚本里用 exec + 文件描述符加锁的写法
这种写法最灵活,适合长脚本中部分代码需要加锁,其余保持并发。
- 先用
exec {fd}>/tmp/lockfile让 bash 自动分配一个未使用的 fd(4.2+ 版本支持) - 再用
flock -x "$fd"加锁,此时当前 shell 进程持有该锁 - 锁住的代码块结束后,用
exec "$fd">&-关闭 fd,自动释放锁 - 示例:
exec {lock_fd}>"/tmp/myscript.lock" flock -x "$lock_fd" echo "开始写共享资源..." echo "$(date): processed" >> /shared/log.txt sleep 2 echo "完成" exec "$lock_fd">&- - 别手动指定 fd 数字(如
exec 3>/tmp/lock),容易和脚本其他重定向冲突
多个脚本共用同一把锁时的坑
看似简单,但实际最容易出问题的地方是锁路径不一致、锁类型混用、或忘记清理残留锁文件。
- 所有脚本必须使用**完全相同的锁文件路径**,包括绝对路径;相对路径在不同工作目录下会指向不同文件
- 不要混用
-s(共享锁)和-x(独占锁):共享锁之间不互斥,两个-s可同时成功 - 锁文件本身不会自动清理,但
flock不依赖文件内容,所以不用管它是否存在;但不要在脚本里rm锁文件——这会导致已持锁进程失效 - 如果脚本崩溃退出,fd 会被内核自动关闭,锁随之释放,无需额外处理
真正要注意的,是所有要互斥的脚本是否真的都走同一套 flock 流程;漏掉一个,整个互斥就形同虚设。











