如果调用了另一个实例,请重新运行bash脚本

时间:2012-06-04 22:24:48

标签: linux bash unix

我有一个可以同时多次调用的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的条件似乎不起作用。

3 个答案:

答案 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)

请参阅Process Management