
flock 是 Linux Shell 脚本中最常用、最轻量的进程级文件锁工具,它基于内核的 advisory locking(建议性锁)机制,无需额外依赖,适合保护单机环境下的临界资源,比如防止脚本重复执行、避免并发写入同一日志或配置文件、协调多个实例访问共享数据等。
为什么用 flock 而不是自建锁文件?
手动 touch 一个 lock 文件再检查存在性,存在竞态条件(race condition):两个进程几乎同时判断“锁不存在”,然后都创建锁并继续执行——实际就失效了。而 flock 的加锁操作是原子的,由内核保证同一时刻只有一个进程能成功获取锁。
它不依赖文件内容或路径是否存在,而是作用于打开的文件描述符,进程退出时自动释放(除非显式指定不继承),安全性与可靠性远高于手工实现。
基本用法:三种典型模式
1. 包裹命令执行(推荐用于简单场景)
flock /tmp/myscript.lock -c 'your_command_here'
自动打开锁文件、加锁、执行命令、释放锁。若锁已被占用,默认阻塞等待;加 -n 可设为非阻塞(失败立即退出)。
2. 在脚本中显式控制锁生命周期
exec 200>/tmp/myscript.lock
flock -n 200 || { echo "Already running"; exit 1; }
# 后续所有操作都在锁保护下
echo "Doing work..."
sleep 10
# 脚本退出时,fd 200 关闭,锁自动释放
3. 配合 while 循环实现重试或轮询
for i in {1..5}; do
if flock -n 200; then
break
fi
sleep 2
done || { echo "Failed to acquire lock after 5 tries"; exit 1; }
关键注意事项
• 锁粒度是文件描述符,不是文件路径:即使多个脚本打开同一个锁文件,只要使用不同 fd(如 200 和 201),它们互不影响;必须复用同一 fd 才能形成互斥。
• 子进程默认继承锁(除非加 -o):如果用 flock -o,子进程不会持有锁,父进程退出后锁即释放;否则子进程运行期间锁一直有效。
• 不要在管道中直接用 flock:例如 flock /tmp/lk -c 'cmd1 | cmd2' 中,shell 会为管道创建子 shell,可能导致锁提前释放。应改用显式 fd 方式或把整条流水线包进单个 -c 命令中。
• 锁文件本身可任意路径,但需确保所有实例访问同一路径:推荐用绝对路径,避免因工作目录不同导致锁失效。
实用小技巧
• 用 /dev/shm/xxx.lock 存放锁文件:内存文件系统,无磁盘 I/O,更快更干净。
• 结合 $0 或脚本 basename 自动构造锁路径:lockfile="/dev/shm/$(basename "$0").lock",避免硬编码。
• 加锁前先 pidof 或 pgrep 检查残留进程(非必须,但可辅助排障):pgrep -f "$(basename "$0")" | grep -v $$。
• 日志中记录锁状态便于调试:echo "[$(date)] Acquired lock on $lockfile" >> /var/log/myscript.log。










