用于确保在任何给定时间仅运行一个 shell 脚本的 shell 片段 [重复]

Posted

技术标签:

【中文标题】用于确保在任何给定时间仅运行一个 shell 脚本的 shell 片段 [重复]【英文标题】:Shell fragment to make sure only one instance a shell script runs at any given time [duplicate] 【发布时间】:2010-10-31 20:42:10 【问题描述】:

可能重复:Quick-and-dirty way to ensure only one instance of a shell script is running at a time

在以前的工作场所,我们曾经有一个高度精炼的 bash 函数,称为 run-only-once,我们可以将它写入任何长时间运行的 shell 脚本,然后在脚本的开头调用它,它会检查查看脚本是否已经作为另一个进程运行,如果是,则退出并通知 STDOUT。

有没有人可以分享这样的函数/片段?

我们的旧函数(我不再拥有)将检查 /var/run 中的 PID 文件(以 scriptname.$$ 格式),然后使用退出或简单地继续。在存在 PID 文件的情况下,它会进行一些检查以确保进程仍然处于活动状态。它还有一些选项可以控制是否输出通知。

根据记忆,我们的函数只能在 bash 中工作。 /bin/sh 版本的奖励积分。

【问题讨论】:

【参考方案1】:

把它放在脚本的开头

SCRIPTNAME=`basename $0`
PIDFILE=/var/run/$SCRIPTNAME.pid


if [ -f $PIDFILE ]; then
   #verify if the process is actually still running under this pid
   OLDPID=`cat $PIDFILE`
   RESULT=`ps -ef | grep $OLDPID | grep $SCRIPTNAME`  

   if [ -n "$RESULT" ]; then
     echo "Script already running! Exiting"
     exit 255
   fi

fi


#grab pid of this process and update the pid file with it
PID=`ps -ef | grep $SCRIPTNAME | head -n1 |  awk ' print $2; '`
echo $PID > $PIDFILE

最后

if [ -f $PIDFILE ]; then
    rm $PIDFILE
fi

首先检查 pid 文件是否存在,如果存在则退出。如果是这样,则它确认在此脚本名称下使用旧 pid 的进程正在运行,如果是,则退出。如果不是,那么它会继续并使用新的 pid 文件更新脚本。最后的位检查pid文件是否存在并将其删除,以便脚本可以下次运行。

检查 /var/run 的权限是否适合您的脚本,否则在另一个目录中创建 PID 文件。与脚本运行的目录相同即可。

【讨论】:

好答案,我可能会使用它,或者将它与 Nik 指出的问题 185451 的答案结合起来(即我将使用陷阱并杀死 -0)。 还有,能不能不用$$来获取这个进程的PID?【参考方案2】:

有两种方法可以从 shell 执行原子锁。最简单、最便携的是mkdir。如果同名的文件/目录已经存在,创建目录将总是失败,因此只需使用“锁定目录”而不是“锁定文件”即可。

mkdir "$LOCK" ||  echo "Script already running" ; exit 1 ; 

另一种方法是 noclobber 选项,使用set -C 设置。此选项强制 shell 使用 O_EXCL 标志打开文件以进行输出重定向。像这样使用它:

set -C
> "$LOCK" ||  echo "Script already running" ; exit 1 ; 
set +C

您可能更愿意回显当前的 PID 或其他有用的信息来存储在文件中,而不是重定向空命令。

值得记住的是,一些古老的历史 shell 已经破坏了 noclobber 选项 -C 的实现,它不使用 O_EXCL 而是使用错误的非原子检查文件是否存在。在 21 世纪可能不是问题,但您应该注意以防万一。

【讨论】:

【参考方案3】:

在 Linux 中使用 lockfile 实用程序更可靠。

来自手册页:

         ...
         lockfile important.lock
         ...
         access_"important"_to_your_hearts_content
         ...
         rm -f important.lock
         ...

您可以指定重试和等待时间。这是专门为此目的创建的,因此它可以处理竞争条件

【讨论】:

以上是关于用于确保在任何给定时间仅运行一个 shell 脚本的 shell 片段 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

Shell脚本:如果已经运行,请确保不执行脚本[重复]

如何在 shell 脚本中增加版本号?

Shell脚本以仅包含冒号的行结尾?

JavaScript 获取延迟

防止使用同一张信用卡多次购买?

在任何给定时间运行 5 个脚本