linux Shell 中常用 mkdir 原子性创建锁目录实现 并发 控制,成功则执行任务并 trap 自动清理,失败则退出;需加超时检测防死锁,比 touch 更安全可靠。

Linux Shell 中控制并发执行,常用锁文件(lock file)方案来避免多个实例同时运行造成冲突。核心思路是:脚本启动时尝试创建一个唯一锁文件,成功则继续执行,失败则退出或等待;结束前删除锁文件。
锁文件的基本实现逻辑
利用 mkdir 命令的原子性——它在文件系统上创建目录的操作不可分割,天然具备排他性。即使多个进程同时执行 mkdir /tmp/myapp.lock,也只有一个能成功,其余返回失败。这比用 touch + 检查文件是否存在更可靠,因为后者存在竞态条件(check-then-act 问题)。
一个安全可用的锁 封装 函数
可将加锁 / 解锁逻辑封装为函数,提升复用性和健壮性:
LOCK_FILE="/tmp/my_script.lock" <p>acquire_lock() { if mkdir "$LOCK_FILE" 2>/dev/NULL; then echo "Lock acquired" return 0 else echo "Another instance is running, exit." return 1 fi }</p><p>release_lock() { rmdir "$LOCK_FILE" 2>/dev/null}</p><h1> 退出时自动清理锁 </h1><p>trap release_lock EXIT</p> <div class="aritcle_card"> <a class="aritcle_card_img" href="/ai/1905"> <img src="https://img.php.cn/upload/ai_manual/001/246/273/68b6d6c8bb4a9796.jpeg" alt=" 趣问问 AI"> </a> <div class="aritcle_card_info"> <a href="/ai/1905"> 趣问问 AI</a> <p> 免费可用的国内版 chat,AI 写作和 AI 对话 </p> <div class=""> <img src="/static/images/card_xiazai.png" alt=" 趣问问 AI"> <span>91</span> </div> </div> <a href="/ai/1905" class="aritcle_card_btn"> <span> 查看详情 </span> <img src="/static/images/cardxiayige-3.png" alt=" 趣问问 AI"> </a> </div> <h1> 尝试获取锁 </h1><p>if ! acquire_lock; then exit 1 fi</p><h1> 此处写你的主逻辑 </h1><p>echo "Running main task……" sleep 10
进阶考虑:超时与死锁防护
实际生产中需防范锁残留(如脚本异常终止未删锁)。可增加时间戳和超时判断:
- 在锁目录内写入当前时间:
date +%s > "$LOCK_FILE/timestamp" - 加锁前检查旧锁是否超时(例如 300 秒):
find "$LOCK_FILE" -mmin +5 -delete 2>/dev/null - 或用
fuser检查锁文件是否被占用(需配合ln -sf方式建锁,略复杂)
替代方案简要对比
除锁文件外,还有其他轻量级控制方式:
- flock(推荐用于单机简单场景):基于文件描述符的 advisory lock,支持脚本内嵌使用,自动释放,但依赖内核支持且不跨 NFS 稳定
- systemd-run –scope –same-dir:适合已集成 systemd 的环境,通过 cgroup 限制并发
- 数据库 行锁 / redis 分布式 锁:适用于多机协同场景,复杂度高,不属纯 Shell 范畴
锁文件方案简单、兼容性强、无需额外依赖,适合大多数单机定时任务或守护脚本的并发控制。关键是用 mkdir 而非 touch,并配好 trap 清理和超时机制。