2007-02-11
How to do locking in shell scripts
To do simple locking in shell scripts, you need an atomic system call
that fails if the target already exists, and that is directly exposed
in a utility program. Ignoring for a moment what System V did to ln
, there are two good candidates on modern Unix systems:
link(2)
and mkdir(2)
.
Mkdir
is actually the better of the two (because you don't have to
fiddle around with temporary files), but ln
is the more common one,
probably for two reasons:
- with
mkdir
you can't atomically associate some extra information, like a PID, with the lock. You can put a PID file inside the directory, but there will be a time when it doesn't exist although you have the lock. - there was no
mkdir(2)
system call in V7; it was only added in UCB BSD, and didn't make it into System V until fairly late. So for a fair timemkdir
wasn't actually suitable for this, and everyone got into the habit of usingln
.
General locking with mkdir
is simple:
mkdir LOCK 2>/dev/null || exit 0 echo running locked rmdir LOCK
Locking with ln
(ignoring System V) is somewhat more
complicated:
echo $$ >$$ if ln $$ LOCK 2>/dev/null; then echo running locked rm $$ LOCK else rm $$ fi
In both cases you really want a private directory for the locks. If you
have to use a shared directory like /tmp
, I believe the ln
approach
is the only one that can stand up to hostile attacks (provided that you
use something like mktemp
to securely create the temporary file).