避免使用相同bash脚本的两个实例

时间:2014-04-17 16:35:01

标签: linux bash locking

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

我应该使用文件锁机制,例如

touch lockfile
do_work
rm lockfile

那够了吗?

4 个答案:

答案 0 :(得分:3)

您可以使用flock

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

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

答案 1 :(得分:3)

由于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 会创建一个目录(如果该目录尚不存在),如果存在,   它设置退出代码。更重要的是,它完成了所有这一切   原子动作使它适合这种情况。

答案 2 :(得分:1)

它认为你的逻辑更像是:

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

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

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

一个可能的解决方案是noclobber选项,它禁止写入现有文件,从而在更多的情况下完成if子句和touch命令原子时尚。

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

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

答案 3 :(得分:0)

创建锁定文件或失败(无竞争条件),同时方便地在程序的锁定文件中记录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