Possible Duplicate:
Quick-and-dirty way to ensure only one instance of a shell script is running at a time
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.
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.
From memory, our function only worked in bash. Bonus points for a /bin/sh version.
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.
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.
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".
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:
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.
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.
It is more reliable to use the lockfile utility in Linux.
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