一、flock
基础命令格式
flock [选项] <文件|文件描述符> <命令>
# 或
flock [选项] <文件|文件描述符> -c <命令字符串>
二、核心选项及示例说明
1. -s
(共享锁 Shared Lock)
作用 获取共享锁(读锁),允许多进程同时读取,但阻止排他锁。
场景 需要多个进程同时读取某个文件,但要求写入操作互斥。
示例
# 两个终端同时运行此命令不会阻塞 flock -s data.lock -c "cat data.txt; sleep 5"
2. -x
(排他锁 Exclusive Lock )
作用 获取排他锁(写锁),禁止其他进程获取任何类型的锁。
场景 需要对文件进行写入操作时,保证数据一致性。
示例
# 第二个进程会阻塞直到第一个完成 flock -x log.lock -c "echo 'New log entry' >> app.log; sleep 3"
3. -n
(非阻塞 Non-blocking)
作用 非阻塞模式。若无法立即获取锁,立即失败并退出,不会等待。
场景 快速判断资源是否可用,无需等待。
示例
if flock -n 200; then echo "Got lock, doing work..." sleep 2 else echo "Resource busy, exiting." fi 200>data.lock
4. -w <秒数>
(超时等待 Timeout)
作用 指定等待锁的超时时间。超过设定时间仍无法获取锁则放弃。
场景 希望在一定时间内尝试获取锁,避免无限等待。
示例
# 最多等待5秒 if flock -w 5 200; then echo "Lock acquired within 5s" else echo "Timeout! Lock unavailable" fi 200>config.lock
5. -u
(手动解锁 Unlock)
作用 手动释放文件描述符关联的锁(通常配合
exec
使用)。场景 需要更精细控制锁的生命周期。
示例
exec 200>db.lock flock -x 200 # 加排他锁 echo "Writing to DB..." flock -u 200 # 手动释放锁
6. -E <错误码>
(自定义错误码)
作用 定义在超时或非阻塞模式下无法获取锁时返回的退出码。
场景 通过不同错误码区分失败原因,便于脚本处理。
示例
flock -E 66 -w 10 200 || handle_error $?
7. -o
(关闭自动关闭描述符)
作用 保持文件描述符打开,不传递给子进程。
场景 需要在父进程保持锁,而子进程不使用锁时。
示例
( flock -o 200 # 文件描述符200保持打开 echo "Parent keeps lock..." ./child_script.sh # 子进程不继承锁 ) 200>file.lock
三、综合应用案例
案例1:保证单实例运行
# 通过锁文件保证同一时刻只有一个脚本实例运行
LOCK_FILE="/tmp/script.lock"
exec 200>"${LOCK_FILE}"
if ! flock -n 200; then
echo "Another instance is running. Exiting."
exit 1
fi
# 主业务逻辑...
echo "Working..."
sleep 10
案例2:数据库文件读写保护
DB_FILE="app.db"
LOCK_FILE="${DB_FILE}.lock"
query_database() {
local sql="$1"
(
flock -x 200
sqlite3 "${DB_FILE}" "${sql}"
) 200>"${LOCK_FILE}"
}
# 并发安全查询
query_database "SELECT * FROM users;" &
query_database "UPDATE stats SET views=views+1;" &
案例3:带超时的日志追加
LOG_FILE="debug.log"
LOG_LOCK="${LOG_FILE}.lock"
log_message() {
local msg="$1"
(
if flock -w 5 200; then
echo "$(date) - ${msg}" >> "${LOG_FILE}"
else
echo "Logging timeout!" >&2
fi
) 200>"${LOG_LOCK}"
}
# 并行写入测试
for i in {1..5}; do
log_message "Test $i" &
done
四、注意事项
文件描述符管理
exec 200>file.lock # 明确管理文件描述符 flock -x 200 # 使用200而非文件名
锁粒度控制 加锁粒度要尽可能小。例如只锁需要保护的临界区代码。
NFS 文件系统
flock
在 NFS 上的行为可能不可靠,需查阅具体实现文档。
可以通过 man flock
查看完整的官方文档。