Improved code to make a Bash script quit if it detects multiple running instances of itself

I've been using the following code in my Bash scripts to check if another instance of the same script is already running and quit:

if [ "$(pgrep -x $(basename $0))" != "$$" ]; then
  echo "Error: another instance of $(basename $0) is already running"
  exit 1
fi

Realized today that it doesn't always work. For instance, let's say I have scripts named test, test.with.multiple.periods and test_with_underscores:

$ ps aux | sed -n '/test/p'
ak    1186  0.0  0.0  10648  1516 pts/4    S    19:43   0:00 /bin/bash ./test
ak    1192  0.0  0.0  10648  1520 pts/4    S    19:43   0:00 /bin/bash ./test.with.multiple.periods
ak    1196  0.0  0.0  10648  1524 pts/4    S    19:44   0:00 /bin/bash ./test_with_underscores

The pgrep syntax I'd been using will match the first one:

$ pgrep -lx test
1186 test

But return nothing for the other two:

$ pgrep -lx test.with.multiple.periods
$ pgrep -lx test_with_underscores

The -f option fixes that:

$ pgrep -lfx "/bin/bash ./test"
1186 /bin/bash ./test
$ pgrep -lfx "/bin/bash ./test.with.multiple.periods"
1192 /bin/bash ./test.with.multiple.periods
$ pgrep -lfx "/bin/bash ./test_with_underscores"
1196 /bin/bash ./test_with_underscores

With that in mind, the updated version of the code to quit if another instance of the same script is already running, that works with all three examples above, is:

if [ "$(pgrep -fx "/bin/bash $0")" != "$$" ]; then
  echo "Error: another instance of $(basename $0) is already running"
  exit 1
fi

UPDATE 2012-12-13

The above won't work correctly if your script accepts arguments, here's a version that should correctly match scripts launched both with or without arguments:

if [ -z "$@" ]; then
  if [ "$(pgrep -fx "/bin/bash $0")" != "$$" ]; then
    echo "ERROR: another instance of '$(basename $0)' is already running"
    exit 1
  fi
else
  if [ "$(pgrep -fx "/bin/bash $0 $@")" != "$$" ]; then
    echo "ERROR: another instance of '$(basename $0) $@' is already running"
    exit 1
  fi
fi

3 Comments

  • 1. sundar replies at 31st October 2013, 7:19 pm :

    Thanks a lot buddy. You made my life easy. I just made one change in my script: /bin/sh instead of /bin/bash after noticing it on ps -ef Keep up your good work.

  • 2. wes replies at 9th June 2014, 3:52 pm :

    Thanks this helped

  • 3. Anthony replies at 30th December 2014, 2:01 am :

    Thank you it helped me to write a script without any lock file.

Leave a comment

NOTE: Enclose quotes in <blockquote></blockquote>. Enclose code in <pre lang="LANG"></pre> (where LANG is one of these).