2

我有一个可以同时调用多次的 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

我该怎么做呢?在退出之前触摸羊群中的一个文件并将该文件作为第二个 if 的条件似乎不起作用。

4

3 回答 3

2

有一个标志(锁文件)来表示需要做的事情,并始终设置它。有一个由执行部分取消设置的单独标志。

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”,那么您需要创建某种队列。整体结构类似。

于 2012-06-04T22:41:08.530 回答
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

通过将有用的信息直接编码到链接目标中,您可以消除写入文件引入的竞争条件。

也就是说,丹尼斯发布的链接提供了更多有用的信息,您可能应该在编写更多脚本之前尝试理解这些信息。我上面的示例与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
于 2012-06-05T05:20:37.797 回答
0

请参阅流程管理

于 2012-06-04T22:30:54.810 回答