有什么快速而简单的方法可以确保在给定时间内只有一个shell脚本实例在运行?


当前回答

实际上,尽管bmdhacks的答案几乎很好,但在第一次检查锁文件之后和在写入它之前,第二个脚本有轻微的机会运行。它们都将写入锁文件,它们都将运行。以下是如何确保它有效的方法:

lockfile=/var/lock/myscript.lock

if ( set -o noclobber; echo "$$" > "$lockfile") 2> /dev/null ; then
  trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT
else
  # or you can decide to skip the "else" part if you want
  echo "Another instance is already running!"
fi

如果文件已经存在,noclobber选项将确保重定向命令将失败。因此,重定向命令实际上是原子的—您用一个命令写入和检查文件。你不需要在文件的末尾删除锁文件-它会被陷阱删除。我希望这对以后读到它的人有帮助。

另外,我没有看到Mikel已经正确地回答了这个问题,尽管他没有包括trap命令,以减少使用Ctrl-C停止脚本后留下锁文件的机会。这就是完整的解

其他回答

试试下面的方法,

ab=`ps -ef | grep -v grep | grep -wc processname`

然后使用if循环将变量与1匹配。

又快又脏?

#!/bin/sh

if [ -f sometempfile ]
  echo "Already running... will now terminate."
  exit
else
  touch sometempfile
fi

..do what you want here..

rm sometempfile

已经回答了一百万次了,但是另一种方式,不需要外部依赖:

LOCK_FILE="/var/lock/$(basename "$0").pid"
trap "rm -f ${LOCK_FILE}; exit" INT TERM EXIT
if [[ -f $LOCK_FILE && -d /proc/`cat $LOCK_FILE` ]]; then
   // Process already exists
   exit 1
fi
echo $$ > $LOCK_FILE

每次它将当前PID($$)写入锁文件,并在脚本启动时检查进程是否正在使用最新的PID运行。

我发现bmdhack的解决方案是最实用的,至少对我的用例来说是这样。使用flock和lockfile依赖于在脚本终止时使用rm删除lockfile,这不能总是得到保证(例如,kill -9)。

关于bmdhack的解决方案,我要改变一件小事:它强调删除锁文件,但没有说明这对于这个信号量的安全工作是不必要的。他使用kill -0来确保死进程的旧锁文件将被忽略/覆盖。

因此,我的简化解决方案是简单地将以下内容添加到单例的顶部:

## Test the lock
LOCKFILE=/tmp/singleton.lock 
if [ -e ${LOCKFILE} ] && kill -0 `cat ${LOCKFILE}`; then
    echo "Script already running. bye!"
    exit 
fi

## Set the lock 
echo $$ > ${LOCKFILE}

当然,这个脚本仍然有一个缺陷,即可能同时启动的进程存在竞争风险,因为锁定测试和设置操作不是单个原子动作。但是lhunath提出的使用mkdir的解决方案有一个缺陷,即被杀死的脚本可能会留下目录,从而阻止其他实例运行。

使用进程的锁更强大,还可以处理不合理的退出。 只要进程在运行,Lock_file就保持打开状态。一旦进程存在,它将被关闭(通过shell)(即使它被杀死)。 我发现这个方法非常有效:

lock_file=/tmp/`basename $0`.lock

if fuser $lock_file > /dev/null 2>&1; then
    echo "WARNING: Other instance of $(basename $0) running."
    exit 1
fi
exec 3> $lock_file