Bash locking

Intro

Once in a while i want to start a bash script and make sure it one at a time. So searching for solution for creating a lock file in bash, you want to have a solution that doesn't create a race condition.

Explanation

Start defining which lockfile you want to use

export lockfile=/tmp/lockfile.txt

Get pid from lockfile, return empty string if file doesn't exists or is empty For added protection removed character from the file that isn't a number

export lockpid="$(cat "$lockfile" 2>/dev/null | tr -c -d 0-9)"

We check the pid to see if the process is still running, if not than the lock file is stale and we can remote it. We use kill with signal -0 (null) that is the way to test if a process can receive signals.

kill -0 "$lockpid" 2>/dev/null

If the process exists then we just say bye and exit the program otherwise we delete the stale lockfile

We than set the noclobber so that bash doesn't overwrite any files, that way we can try to create a lockfile but if another version of us is earlier we lose

set -o noclobber echo "$$" >"$lockfile"

If we can't save the lockfile just exit the script with lock failed skipping

If everything is good then we should have a lock file with our pid in it. But to make sure we don't have a rare race condition, we wait 2 seconds

sleep 2s

And than we check is the pid in the lockfile is ours....

export lockpid="$(cat "$lockfile" 2>/dev/null | tr -c -d 0-9)"

if test $lockpid -ne $$; then

And ofcourse if it isn't our lock file we stop here with lock failed.

We are almost ready just add a trap so that we clean up the lock file is when we are ready

trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT

And remove the noclobber settings so that we can override files again

set +o noclobber

And then just start your script.....

The scripts

Ok just to give you some the start script

!/bin/bash

export lockfile=/tmp/lockfile.txt

export lockpid="$(cat "$lockfile" 2>/dev/null | tr -c -d 0-9)"

# if lockpid exists then check if pid still active
if test -n "$lockpid"; then
  if ! kill -0 "$lockpid" 2>/dev/null; then
     echo "cleanup stale: lockfile: $lockfile"
     rm "$lockfile"
  else
     echo "lock file exits."
     echo "skipping"
     exit 0
  fi
fi

# create lockfile, using noclobber no exit if file allready exits.
set -o noclobber
if ! echo "$$" >"$lockfile" 2>/dev/null; then
  echo "lock failed."
  echo "skipping"
  exit 0
fi

sleep 2s # just to settle down
# just for sure check if the lockfile has our pid file
export lockpid="$(cat "$lockfile" 2>/dev/null | tr -c -d 0-9)"
if test $lockpid -ne $$; then
  echo "lock failed."
  echo "skipping"
  exit 0
fi

trap 'rm -f "$lockfile"; exit $?' INT TERM EXIT
set +o noclobber

# script

exit 0

Richard

Previous Post Next Post