Quick-and-dirty way to ensure only one instance of a shell script is running at a time Quick-and-dirty way to ensure only one instance of a shell script is running at a time bash bash

Quick-and-dirty way to ensure only one instance of a shell script is running at a time


Use flock(1) to make an exclusive scoped lock a on file descriptor. This way you can even synchronize different parts of the script.

#!/bin/bash(  # Wait for lock on /var/lock/.myscript.exclusivelock (fd 200) for 10 seconds  flock -x -w 10 200 || exit 1  # Do stuff) 200>/var/lock/.myscript.exclusivelock

This ensures that code between ( and ) is run only by one process at a time and that the process doesn’t wait too long for a lock.

Caveat: this particular command is a part of util-linux. If you run an operating system other than Linux, it may or may not be available.


All approaches that test the existence of "lock files" are flawed.

Why? Because there is no way to check whether a file exists and create it in a single atomic action. Because of this; there is a race condition that WILL make your attempts at mutual exclusion break.

Instead, you need to use mkdir. mkdir creates a directory if it doesn't exist yet, and if it does, it sets an exit code. More importantly, it does all this in a single atomic action making it perfect for this scenario.

if ! mkdir /tmp/myscript.lock 2>/dev/null; then    echo "Myscript is already running." >&2    exit 1fi

For all details, see the excellent BashFAQ: http://mywiki.wooledge.org/BashFAQ/045

If you want to take care of stale locks, fuser(1) comes in handy. The only downside here is that the operation takes about a second, so it isn't instant.

Here's a function I wrote once that solves the problem using fuser:

#       mutex file## Open a mutual exclusion lock on the file, unless another process already owns one.## If the file is already locked by another process, the operation fails.# This function defines a lock on a file as having a file descriptor open to the file.# This function uses FD 9 to open a lock on the file.  To release the lock, close FD 9:# exec 9>&-#mutex() {    local file=$1 pid pids     exec 9>>"$file"    { pids=$(fuser -f "$file"); } 2>&- 9>&-     for pid in $pids; do        [[ $pid = $$ ]] && continue        exec 9>&-         return 1 # Locked by a pid.    done }

You can use it in a script like so:

mutex /var/run/myscript.lock || { echo "Already running." >&2; exit 1; }

If you don't care about portability (these solutions should work on pretty much any UNIX box), Linux' fuser(1) offers some additional options and there is also flock(1).


Here's an implementation that uses a lockfile and echoes a PID into it. This serves as a protection if the process is killed before removing the pidfile:

LOCKFILE=/tmp/lock.txtif [ -e ${LOCKFILE} ] && kill -0 `cat ${LOCKFILE}`; then    echo "already running"    exitfi# make sure the lockfile is removed when we exit and then claim ittrap "rm -f ${LOCKFILE}; exit" INT TERM EXITecho $$ > ${LOCKFILE}# do stuffsleep 1000rm -f ${LOCKFILE}

The trick here is the kill -0 which doesn't deliver any signal but just checks if a process with the given PID exists. Also the call to trap will ensure that the lockfile is removed even when your process is killed (except kill -9).