Possible Duplicate:
Quick-and-dirty way to ensure only one instance of a shell script is running at a time可能重复:确保一次只运行一个shell脚本实例的快速和脏方法
At a previous workplace we used to have a highly-refined bash function called run-only-once that we could write into any long-running shell script, and then call it at the start of the script, which would check to see whether the script was already running as another process, and if so exit with a notification to STDOUT.
在以前的工作场所,我们曾经有一个高度精炼的bash函数叫做run-only-once,我们可以写入任何长时间运行的shell脚本,然后在脚本的开头调用它,这将检查是否脚本已作为另一个进程运行,如果是,则退出并向STDOUT发送通知。
Does anyone have a function/fragment like this they could share?
有没有人有他们可以共享的功能/片段?
Our old function (which I no longer have) would check for a PID file (in scriptname.$$ format) in /var/run, and use then either exit or simply continue. In the case where a PID file existed, it would do some checks to make sure that the process was still active. It also had a few options for controlling whether a notification was output at all.
我们的旧函数(我不再拥有)将检查/ var / run中的PID文件(以scriptname。$$格式),然后使用exit或者只是继续。在存在PID文件的情况下,它会进行一些检查以确保该进程仍处于活动状态。它还有几个选项来控制是否输出通知。
From memory, our function only worked in bash. Bonus points for a /bin/sh version.
从内存来看,我们的功能只适用于bash。 / bin / sh版本的加分点。
3 个解决方案
#1
Put this at the start of the script
把它放在脚本的开头
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}
and at the end
最后
if [ -f ${PIDFILE} ]; then
rm ${PIDFILE}
fi
This first of all checks for the existence of the pid file and exits if it's present. If so then it confirms that a process under this script name with the old pid is running and exits if so. If not then it carries on and updates the script with the new pid file. The bit at the end checks for the existence of the pid file and deletes it, so the script can run next time.
首先检查pid文件是否存在,如果存在则退出。如果是,则确认此脚本名称下的进程正在运行,如果是,则退出。如果没有,那么它继续并使用新的pid文件更新脚本。最后一位检查pid文件是否存在并删除它,因此脚本可以在下次运行。
Check permissions on /var/run are OK for your script though, otherwise create the PID file in another directory. Same directory as the script runs in would be fine.
检查/ var / run的权限对于您的脚本是否正常,否则在另一个目录中创建PID文件。与脚本运行相同的目录也没问题。
#2
There are two ways to do atomic locks from the shell. The simplest and most portable is mkdir
. Creation of a directory will always fail if a file/directory by that name already exists, so simply use a "lock directory" instead of "lock file".
从shell执行原子锁有两种方法。最简单,最便携的是mkdir。如果已存在该名称的文件/目录,则创建目录将始终失败,因此只需使用“锁定目录”而不是“锁定文件”。
mkdir "$LOCK" || { echo "Script already running" ; exit 1 ; }
The other method is the noclobber option, set using set -C
. This option forces the shell to open files for output redirection with the O_EXCL
flag. Use it like this:
另一种方法是noclobber选项,使用set -C设置。此选项强制shell使用O_EXCL标志打开文件以进行输出重定向。像这样用它:
set -C
> "$LOCK" || { echo "Script already running" ; exit 1 ; }
set +C
Rather than redirecting a null command, you might prefer to echo the current PID or something else useful to be stored in the file.
您可能更愿意回显当前的PID或其他有用的内容以存储在文件中,而不是重定向空命令。
It's worth keeping in mind that some ancient historic shells have broken implementations of the noclobber option -C
which do not use O_EXCL
but instead buggy non-atomic checks for file existence. Probably not an issue in the 21st century, but you should be aware just in case.
值得注意的是,一些古老的历史性shell已经破坏了noclobber选项-C的实现,它们不使用O_EXCL,而是使用错误的非原子检查文件存在。可能不是21世纪的问题,但你应该意识到以防万一。
#3
It is more reliable to use the lockfile utility in Linux.
在Linux中使用lockfile实用程序更可靠。
From the man page:
从手册页:
... lockfile important.lock ... access_"important"_to_your_hearts_content ... rm -f important.lock ...
You can specify retries and wait times. This was specifically created for this purpose so it takes care of race conditions
您可以指定重试和等待时间。这是专门为此目的而创建的,因此它可以处理竞争条件
#1
Put this at the start of the script
把它放在脚本的开头
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}
and at the end
最后
if [ -f ${PIDFILE} ]; then
rm ${PIDFILE}
fi
This first of all checks for the existence of the pid file and exits if it's present. If so then it confirms that a process under this script name with the old pid is running and exits if so. If not then it carries on and updates the script with the new pid file. The bit at the end checks for the existence of the pid file and deletes it, so the script can run next time.
首先检查pid文件是否存在,如果存在则退出。如果是,则确认此脚本名称下的进程正在运行,如果是,则退出。如果没有,那么它继续并使用新的pid文件更新脚本。最后一位检查pid文件是否存在并删除它,因此脚本可以在下次运行。
Check permissions on /var/run are OK for your script though, otherwise create the PID file in another directory. Same directory as the script runs in would be fine.
检查/ var / run的权限对于您的脚本是否正常,否则在另一个目录中创建PID文件。与脚本运行相同的目录也没问题。
#2
There are two ways to do atomic locks from the shell. The simplest and most portable is mkdir
. Creation of a directory will always fail if a file/directory by that name already exists, so simply use a "lock directory" instead of "lock file".
从shell执行原子锁有两种方法。最简单,最便携的是mkdir。如果已存在该名称的文件/目录,则创建目录将始终失败,因此只需使用“锁定目录”而不是“锁定文件”。
mkdir "$LOCK" || { echo "Script already running" ; exit 1 ; }
The other method is the noclobber option, set using set -C
. This option forces the shell to open files for output redirection with the O_EXCL
flag. Use it like this:
另一种方法是noclobber选项,使用set -C设置。此选项强制shell使用O_EXCL标志打开文件以进行输出重定向。像这样用它:
set -C
> "$LOCK" || { echo "Script already running" ; exit 1 ; }
set +C
Rather than redirecting a null command, you might prefer to echo the current PID or something else useful to be stored in the file.
您可能更愿意回显当前的PID或其他有用的内容以存储在文件中,而不是重定向空命令。
It's worth keeping in mind that some ancient historic shells have broken implementations of the noclobber option -C
which do not use O_EXCL
but instead buggy non-atomic checks for file existence. Probably not an issue in the 21st century, but you should be aware just in case.
值得注意的是,一些古老的历史性shell已经破坏了noclobber选项-C的实现,它们不使用O_EXCL,而是使用错误的非原子检查文件存在。可能不是21世纪的问题,但你应该意识到以防万一。
#3
It is more reliable to use the lockfile utility in Linux.
在Linux中使用lockfile实用程序更可靠。
From the man page:
从手册页:
... lockfile important.lock ... access_"important"_to_your_hearts_content ... rm -f important.lock ...
You can specify retries and wait times. This was specifically created for this purpose so it takes care of race conditions
您可以指定重试和等待时间。这是专门为此目的而创建的,因此它可以处理竞争条件