[ACCEPTED]-How to make sure only one instance of a Bash script is running at a time?-scheduled-tasks
You want a pid file, maybe something like 1 this:
pidfile=/path/to/pidfile
if [ -f "$pidfile" ] && kill -0 `cat $pidfile` 2>/dev/null; then
echo still running
exit 1
fi
echo $$ > $pidfile
I think you need to use lockfile command. See 22 using lockfiles in shell scripts (BASH) or http://www.davidpashley.com/articles/writing-robust-shell-scripts.html.
The second article uses "hand-made 21 lock file" and shows how to catch script 20 termination & releasing the lock; although 19 using lockfile -l <timeout seconds>
will probably be a good enough alternative 18 for most cases.
Example of usage without 17 timeout:
lockfile script.lock
<do some stuff>
rm -f script.lock
Will ensure that any second script 16 started during this one will wait indefinitely 15 for the file to be removed before proceeding.
If 14 we know that the script should not run more 13 than X seconds, and the script.lock
is still there, that 12 probably means previous instance of the 11 script was killed before it removed script.lock
. In 10 that case we can tell lockfile
to force re-create 9 the lock after a timeout (X = 10 below):
lockfile -l 10 /tmp/mylockfile
<do some stuff>
rm -f /tmp/mylockfile
Since 8 lockfile
can create multiple lock files, there is 7 a parameter to guide it how long it should 6 wait before retrying to acquire the next 5 file it needs (-<sleep before retry, seconds>
and -r <number of retries>
). There is also a parameter 4 -s <suspend seconds>
for wait time when the lock has been removed 3 by force (which kind of complements the 2 timeout used to wait before force-breaking 1 the lock).
You can use the run-one
package, which provides 2 run-one
, run-this-one
and keep-one-running
.
The package: https://launchpad.net/ubuntu/+source/run-one
The blog introducing 1 it: http://blog.dustinkirkland.com/2011/02/introducing-run-one-and-run-this-one.html
Write the process id into a file and then 2 when a new instance starts, check the file 1 to see if the old instance is still running.
(
if flock -n 9
then
echo 'Not doing the critical operation (lock present).'
exit;
fi
# critical section goes here
) 9>'/run/lock/some_lock_file'
rm -f '/run/lock/some_lock_file'
From example in flock(1) man page. Very 1 practical for using in shell scripts.
I just wrote a tool that does this: https://github.com/ORESoftware/quicklock
writing 6 a good one takes about 15 loc, so not something 5 you want to include in every shell script.
basically 4 works like this:
$ ql_acquire_lock
the above calls this bash 3 function:
function ql_acquire_lock {
set -e;
name="${1:-$PWD}" # the lock name is the first argument, if that is empty, then set the lockname to $PWD
mkdir -p "$HOME/.quicklock/locks"
fle=$(echo "${name}" | tr "/" _)
qln="$HOME/.quicklock/locks/${fle}.lock"
mkdir "${qln}" &> /dev/null || { echo "${ql_magenta}quicklock: could not acquire lock with name '${qln}'${ql_no_color}."; exit 1; }
export quicklock_name="${qln}"; # export the var *only if* above mkdir command succeeds
trap on_ql_trap EXIT;
}
when the script exits, it automatically 2 releases the lock using trap
function on_ql_trap {
echo "quicklock: process with pid $$ was trapped.";
ql_release_lock
}
to manually 1 release the lock at will, use ql_release_lock
:
function ql_maybe_fail {
if [[ "$1" == "true" ]]; then
echo -e "${ql_magenta}quicklock: exiting with 1 since fail flag was set for your 'ql_release_lock' command.${ql_no_color}"
exit 1;
fi
}
function ql_release_lock () {
if [[ -z "${quicklock_name}" ]]; then
echo -e "quicklock: no lockname was defined. (\$quicklock_name was not set).";
ql_maybe_fail "$1";
return 0;
fi
if [[ "$HOME" == "${quicklock_name}" ]]; then
echo -e "quicklock: dangerous value set for \$quicklock_name variable..was equal to user home directory, not good.";
ql_maybe_fail "$1"
return 0;
fi
rm -r "${quicklock_name}" &> /dev/null &&
{ echo -e "quicklock: lock with name '${quicklock_name}' was released."; } ||
{ echo -e "quicklock: no lock existed for lockname '${quicklock_name}'."; ql_maybe_fail "$1"; }
trap - EXIT # clear/unset trap
}
I suggest using flock
, but in a different way 3 than suggested by @Josef Kufner. I think 2 this is quite easy and flock
should be available 1 on most systems by default:
flock -n lockfile myscript.sh
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.