在bash下进行锁定的简单且看似可靠的方法是:
exec 9>>lockfile
flock 9
然而,bash臭名昭着地将这样的fd锁传播给所有分叉的东西,包括已执行的程序等。
有没有办法告诉bash不要复制fd?锁定附加到fd是很好的,当程序终止时,无论它如何被终止,它都会被删除。
我知道我可以做类似的事情:
run_some_prog 9>&-
但这很乏味。
有没有更好的解决方案?
答案 0 :(得分:8)
您可以使用-o
命令行选项flock(1)
(长选项--close
,这可能更适合在脚本中编写自我文档性质)来指定该文件在通过flock(1)
执行命令之前应该关闭描述符:
-o, --close
Close the file descriptor on which the lock is held
before executing command. This is useful if command
spawns a child process which should not be holding
the lock.
答案 1 :(得分:4)
显然flock -o FD
无法解决问题。在同一个shell脚本中摆脱多余的FD以获取后续命令的技巧是将剩余部分包装成关闭FD的部分,如下所示:
var=outside
exec 9>>lockfile
flock -n 9 || exit
{
: commands which do not see FD9
var=exported
# exit would exit script
# see CLUMSY below outside this code snippet
} 9<&-
# $var is "exported"
# drop lock closing the FD
exec 9<&-
: remaining commands without lock
这有点CLUMSY
,因为FD的关闭到目前为止与锁分开。
你可以重构这个失去“自然”命令流但是把所有东西放在一起的东西:
functions_running_with_lock()
{
: commands which do not see FD9
var=exported
# exit would exit script
}
var=outside
exec 9>>lockfile
flock -n 9 || exit
functions_running_with_lock 9<&-
# $var is "exported"
# drop lock closing the FD
exec 9<&-
: remaining commands without lock
一个更好的写作,保持自然命令流动以牺牲另一个分支加上一个额外的过程和一点点不同的工作流程,这通常很方便。 但是这不允许在外壳中设置变量:
var=outside
exec 9>>lockfile
flock -n 9 || exit
(
exec 9<&-
: commands which do not see FD9
var=exported
# exit does not interrupt the whole script
exit
var=neverreached
)
# optionally test the ret if the parentheses using $?
# $var is "outside" again
# drop lock closing the FD
exec 9<&-
: remaining commands without lock
顺便说一句,如果你真的想确定bash
没有引入额外的文件描述符(“隐藏”已关闭的FD并跳过真正的分支),例如,如果你执行某个守护程序然后会持有锁定永远,推荐后一种变体,只是为了确定。 lsof -nP
和strace your_script
是您的朋友。
答案 2 :(得分:1)
在bash中没有办法将FD标记为close-on-exec,所以不,没有更好的解决方案。
答案 3 :(得分:1)
-o
不适用于文件描述符,它只适用于文件。您必须使用-u
来解锁文件描述符。
我的工作是:
# start of the lock sections
LOCKFILE=/tmp/somelockfile
exec 8>"$LOCKFILE"
if ! flock -n 8;then
echo Rejected # for testing, remove this later
exit # exit, since we don't have lock
fi
# some code which shouldn't run in parallel
# End of lock section
flock -u 8
rm -f "$LOCKFILE"
这样,文件描述符将由进行锁定的进程关闭,并且由于每个其他进程都将退出,这意味着只有持有锁的进程才会解锁文件描述符并删除锁定文件。