我有一个可以同时多次调用的bash脚本。为了保护脚本访问的状态信息(保存在/tmp
文件中),我使用这样的文件锁定:
do_something()
{
...
}
// Check if there are any other instances of the script; if so exit
exec 8>$LOCK
if ! flock -n -x 8; then
exit 1
fi
// script does something...
do_something
现在,在运行此脚本时调用的任何其他实例都会退出。如果有n次同时调用,我希望脚本只运行一次,而不是n次,如下所示:
do_something()
{
...
}
// Check if there are any other instances of the script; if so exit
exec 8>$LOCK
if ! flock -n -x 8; then
exit 1
fi
// script does something...
do_something
// check if another instance was invoked, if so re-run do_something again
if [ condition ]; then
do_something
fi
我该怎么做呢?在退出之前触摸flock中的文件并将该文件作为第二个if的条件似乎不起作用。
答案 0 :(得分:2)
有一个标志(lockfile)来表示事情需要做的事情,并且总是设置它。有一个单独的标志,由执行部分取消设置。
REQUEST_FILE=/tmp/please_do_something
LOCK_FILE=/tmp/doing_something
# request running
touch $REQUEST_FILE
# lock and run
if ln -s /proc/$$ $LOCK_FILE 2>/dev/null ; then
while [ -e $REQUEST_FILE ]; do
do_something
rm $REQUEST_FILE
done
rm $LOCK_FILE
fi
如果要确保每次运行整个脚本时“do_something”只运行一次,那么您需要创建某种类型的队列。总体结构类似。
答案 1 :(得分:2)
他们不是最喜欢的,但我一直都是制作锁定文件的象征性链接的粉丝,因为它们是原子的。例如:
lockfile=/var/run/`basename $0`.lock
if ! ln -s "pid=$$ when=`date '+%s'` status=$something" "$lockfile"; then
echo "Can't set lock." >&2
exit 1
fi
通过将有用信息直接编码到链接目标中,可以消除通过写入文件引入的竞争条件。
也就是说,Dennis发布的链接提供了更多有用的信息,您应该在编写更多脚本之前尝试理解这些信息。我上面的示例与BashFAQ/045有关,建议使用mkdir
执行类似操作。
如果我理解你的问题,那么你可以通过使用两个锁定文件来实现你想要做的事情(稍微不可靠)。如果设置第一个锁失败,我们尝试第二个锁。如果设置第二个锁失败,我们退出。如果第一个锁在我们检查之后但在检查第二个存在锁之前被删除,则存在错误。如果您接受这种错误级别,那就太棒了。
这是未经测试的;但对我来说看起来很合理。
#!/usr/local/bin/bash
lockbase="/tmp/test.lock"
setlock() {
if ln -s "pid=$$" "$lockbase".$1 2>/dev/null; then
trap "rm \"$lockbase\".$1" 0 1 2 5 15
else
return 1
fi
}
if setlock 1 || setlock 2; then
echo "I'm in!"
do_something_amazing
else
echo "No lock - aborting."
fi
答案 2 :(得分:0)