![在 shell 脚本中聚集文件描述符](https://linux22.com/image/89551/%E5%9C%A8%20shell%20%E8%84%9A%E6%9C%AC%E4%B8%AD%E8%81%9A%E9%9B%86%E6%96%87%E4%BB%B6%E6%8F%8F%E8%BF%B0%E7%AC%A6.png)
我以为这会给我不间断的begin-end
配对,但事实并非如此:
#!/bin/bash
fun()(
flock 1 || { echo >&2 "$BASHPID: FAIL: $?"; exit 1; }
echo "$BASHPID begin"
sleep 1;
echo "$BASHPID end"
)
fun &
fun &
fun &
fun &
fun &
fun &
fun &
fun &
fun &
wait
我究竟做错了什么?
答案1
这种方法有效:
fun()(
(flock 9 || { echo >&2 "$BASHPID: FAIL: $?"; exit 1; }
echo "$BASHPID begin"
sleep 1;
echo "$BASHPID end"
) 9>test
)
这可以确保只要需要保护的命令尚未完成,锁定的文件就不会关闭。 (显然你应该更换test
更合适的东西,例如使用mktemp
。)
答案2
失败的原因可以在man 2 flock
:
由flock()创建的锁与打开的文件描述相关联(参见open(2))。这意味着重复的文件描述符(例如,由 fork(2) 或 dup(2) 创建的)引用相同的锁,并且可以使用这些描述符中的任何一个来修改或释放该锁。
这意味着,由于所有进程都继承相同的文件描述符,因此当其中一个进程进行锁定时,它们都会共享该文件描述符。两次锁定同一个文件描述符是无操作的。
我通常的解决方案是锁定脚本本身(尽管如果您同时运行脚本多次,这确实会带来问题)。
#!/bin/bash
fun()(
exec 3<"$0"
flock 3 || { echo >&2 "$BASHPID: FAIL: $?"; exit 1; }
echo "$BASHPID begin"
sleep 1;
echo "$BASHPID end"
)
fun &
fun &
fun &
fun &
fun &
fun &
fun &
fun &
fun &
wait