What is the simplest/best way to ensure only one instance of a given script is running - assuming it's Bash on Linux?
At the moment I'm doing:
ps -C script.name.sh > /dev/null 2>&1 || ./script.name.sh
but it has several issues:
-C
checks only first 14 characters of process nameOf course, I can write my own pidfile handling, but I sense that there should be a simple way to do it.
Advisory locking has been used for ages and it can be used in bash scripts. I prefer simple flock
(from util-linux[-ng]
) over lockfile
(from procmail
). And always remember about a trap on exit (sigspec == EXIT
or 0
, trapping specific signals is superfluous) in those scripts.
In 2009 I released my lockable script boilerplate (originally available at my wiki page, nowadays available as gist). Transforming that into one-instance-per-user is trivial. Using it you can also easily write scripts for other scenarios requiring some locking or synchronization.
Here is the mentioned boilerplate for your convenience.
#!/bin/bash
# SPDX-License-Identifier: MIT
## Copyright (C) 2009 Przemyslaw Pawelczyk <[email protected]>
##
## This script is licensed under the terms of the MIT license.
## https://opensource.org/licenses/MIT
#
# Lockable script boilerplate
### HEADER ###
LOCKFILE="/var/lock/`basename $0`"
LOCKFD=99
# PRIVATE
_lock() { flock -$1 $LOCKFD; }
_no_more_locking() { _lock u; _lock xn && rm -f $LOCKFILE; }
_prepare_locking() { eval "exec $LOCKFD>\"$LOCKFILE\""; trap _no_more_locking EXIT; }
# ON START
_prepare_locking
# PUBLIC
exlock_now() { _lock xn; } # obtain an exclusive lock immediately or fail
exlock() { _lock x; } # obtain an exclusive lock
shlock() { _lock s; } # obtain a shared lock
unlock() { _lock u; } # drop a lock
### BEGIN OF SCRIPT ###
# Simplest example is avoiding running multiple instances of script.
exlock_now || exit 1
# Remember! Lock file is removed when one of the scripts exits and it is
# the only script holding the lock or lock is not acquired at all.