【问题标题】:Avoiding two instances of the same bash script避免同一 bash 脚本的两个实例
【发布时间】:2014-06-02 01:18:30
【问题描述】:

在运行 shell 脚本时,我想绝对确定在给定时间只运行它的一个实例。

我应该采用 文件锁定 机制吗,比如

touch lockfile
do_work
rm lockfile

够了吗?

【问题讨论】:

  • Here's 一种方式。不过我不是很喜欢。

标签: linux bash locking


【解决方案1】:

您可以为此使用flock

 (
  flock -s 200
  # .... commands executed under lock....
 )200>/var/lock/mylockfile

它在 Util-linux 下一代包装下可用... http://en.wikipedia.org/wiki/Util-linux

【讨论】:

  • flock 在我的系统上似乎不存在。即使是谷歌搜索,我也只发现了sys/file.h clib。你能附上一个链接吗?
【解决方案2】:

由于flock 没有安装在我使用的某些系统上——我经常在 Ubuntu(有它)和 Mac OS X(没有)之间切换——我使用这个简单的框架没有任何实际问题:

LOCK_NAME="MY_GREAT_BASH_SCRIPT"
LOCK_DIR='/tmp/'${LOCK_NAME}.lock
PID_FILE=${LOCK_DIR}'/'${LOCK_NAME}'.pid'

if mkdir ${LOCK_DIR} 2>/dev/null; then
    # If the ${LOCK_DIR} doesn't exist, then start working & store the ${PID_FILE}
    echo $$ > ${PID_FILE}

    echo "Hello world!"

    rm -rf ${LOCK_DIR}
    exit
else
    if [ -f ${PID_FILE} ] && kill -0 $(cat ${PID_FILE}) 2>/dev/null; then
        # Confirm that the process file exists & a process
        # with that PID is truly running.
        echo "Running [PID "$(cat ${PID_FILE})"]" >&2
        exit
    else
        # If the process is not running, yet there is a PID file--like in the case
        # of a crash or sudden reboot--then get rid of the ${LOCK_DIR}
        rm -rf ${LOCK_DIR}
        exit
    fi
fi

这个想法是一般核心——我有echo "Hello world!"——是你脚本的核心所在。其余部分基本上是基于mkdir 的锁定机制。对is in this answer概念的很好解释:

mkdir 如果目录不存在,则创建一个目录,如果存在, 它设置了一个退出代码。更重要的是,它在一个单一的 原子动作使其非常适合这种情况。

【讨论】:

    【解决方案3】:

    它认为你的逻辑更像是:

    if [ ! -e lockfile ]; then
        touch lockfile
        do_work
        rm lockfile
    fi
    

    但请注意,即使这样还不够。事实上,它为微妙的错误铺平了道路。由于整个事情不是原子的,第二个进程最好在if 子句之后但在touch 之前开始。

    你的想法的一个不太天真的实现会尝试获取锁操作的原子性。这可以在 Bash 中完成。

    一个可能的解决方案是noclobber 选项,它禁止写入已经存在的文件,从而以更原子的方式完成if 子句和touch 命令。

    我的锁定获取代码将如下所示:

    if ! ( set -o noclobber; echo > lockfile ) exit
    

    【讨论】:

      【解决方案4】:

      在方便地在程序的锁定文件中记录 shell 的 PID 时,要么创建锁定文件,要么失败(不可能出现竞争条件)。如果程序收到任何列出的信号,它就会清理

      #!/bin/bash
      
      # Garbage clean up with trap given any of these SIGNALS
      # INT   Pressing Control-C      kill -2 pid
      # TERM  Termination signal      kill -15 pid
      # EXIT  Shell exit
      
      LockFile="/tmp/${0}.lock" 
      if ( set -o noclobber; echo "$$" > "$LockFile") 2> /dev/null; then
          trap 'rm -f "$LockFile"; exit $?' INT TERM EXIT
      else
          echo -e "Program \"$0\" already running"
          exit 1
      fi
      

      【讨论】:

        猜你喜欢
        • 2010-09-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-07-30
        • 1970-01-01
        • 2020-11-03
        相关资源
        最近更新 更多