How to check if another instance of my shell script is running

114,023

Solution 1

An easier way to check for a process already executing is the pidof command.

if pidof -x "abc.sh" >/dev/null; then
    echo "Process already running"
fi

Alternatively, have your script create a PID file when it executes. It's then a simple exercise of checking for the presence of the PID file to determine if the process is already running.

#!/bin/bash
# abc.sh

mypidfile=/var/run/abc.sh.pid

# Could add check for existence of mypidfile here if interlock is
# needed in the shell script itself.

# Ensure PID file is removed on program exit.
trap "rm -f -- '$mypidfile'" EXIT

# Create a file with current PID to indicate that process is running.
echo $$ > "$mypidfile"

...

Update: The question has now changed to check from the script itself. In this case, we would expect to always see at least one abc.sh running. If there is more than one abc.sh, then we know that process is still running. I'd still suggest use of the pidof command which would return 2 PIDs if the process was already running. You could use grep to filter out the current PID, loop in the shell or even revert to just counting PIDs with wc to detect multiple processes.

Here's an example:

#!/bin/bash

for pid in $(pidof -x abc.sh); do
    if [ $pid != $$ ]; then
        echo "[$(date)] : abc.sh : Process is already running with PID $pid"
        exit 1
    fi
done

Solution 2

I you want the "pidof" method, here is the trick:

    if pidof -o %PPID -x "abc.sh">/dev/null; then
        echo "Process already running"
    fi

Where the -o %PPID parameter tells to omit the pid of the calling shell or shell script. More info in the pidof man page.

Solution 3

Here's one trick you'll see in various places:

status=`ps -efww | grep -w "[a]bc.sh" | awk -vpid=$$ '$2 != pid { print $2 }'`
if [ ! -z "$status" ]; then
    echo "[`date`] : abc.sh : Process is already running"
    exit 1;
fi

The brackets around the [a] (or pick a different letter) prevent grep from finding itself. This makes the grep -v grep bit unnecessary. I also removed the grep -v $$ and fixed the awk part to accomplish the same thing.

Solution 4

Someone please shoot me down if I'm wrong here

I understand that the mkdir operation is atomic, so you could create a lock directory

#!/bin/sh
lockdir=/tmp/AXgqg0lsoeykp9L9NZjIuaqvu7ANILL4foeqzpJcTs3YkwtiJ0
mkdir $lockdir  || {
    echo "lock directory exists. exiting"
    exit 1
}
# take pains to remove lock directory when script terminates
trap "rmdir $lockdir" EXIT INT KILL TERM

# rest of script here

Solution 5

Here's how I do it in a bash script:

if ps ax | grep $0 | grep -v $$ | grep bash | grep -v grep
then
    echo "The script is already running."
    exit 1
fi

This allows me to use this snippet for any bash script. I needed to grep bash because when using with cron, it creates another process that executes it using /bin/sh.

Share:
114,023

Related videos on Youtube

Jatin Bodarya
Author by

Jatin Bodarya

Updated on June 12, 2021

Comments

  • Jatin Bodarya
    Jatin Bodarya almost 3 years

    GNU bash, version 1.14.7(1)

    I have a script is called "abc.sh" I have to check this from abc.sh script only... inside it I have written following statement

    status=`ps -efww | grep -w "abc.sh" | grep -v grep | grep -v $$ | awk '{ print $2 }'`
    if [ ! -z "$status" ]; then
            echo "[`date`] : abc.sh : Process is already running"
            exit 1;
    fi
    

    I know it's wrong because every time it exits as it found its own process in 'ps' how to solve it? how can I check that script is already running or not from that script only ?

    • lc2817
      lc2817 almost 11 years
      The PID of the running process is stored in $$, just ignore it from the list grep -v $$
    • Grzegorz Żur
      Grzegorz Żur almost 11 years
      It is simpler to use some lock file. If file is present another copy is running. Just make sure the file is removed.
    • Jatin Bodarya
      Jatin Bodarya almost 11 years
      Its not safe way to check file in my case..so I suppose to use this way
    • Adam Siemion
      Adam Siemion almost 11 years
      What is the issue with this script? It seems to be correct, you are ignoring the PID of the current process and only checking if there is any other abc.sh process.
    • Jatin Bodarya
      Jatin Bodarya almost 11 years
      wrong is I suppose to check from this script only.... so every time It checks its own PID and exits !!!
    • twalberg
      twalberg almost 11 years
      @Grzegorz While on the surface a lock file may seem simpler, it isn't always so easy to use a lock file right, making sure that it always gets cleaned up correctly, no matter how the program died, or checking to see if it can be overridden when necessary... Getting it 100% right in all cases is actually rather difficult. Although, this is a shell script, so 90% may be downright acceptable...
    • Grzegorz Żur
      Grzegorz Żur almost 11 years
      @twalberg I agree it might be troublesome. I think using pid file will be better, as we can check if it is valid even if it was not cleaned. My vote goes to pid file answer.
    • user
      user almost 10 years
  • Jatin Bodarya
    Jatin Bodarya almost 11 years
    and what if another script "xyzabc.sh" is also running at the same time ? This answer is good but not so safe.
  • Austin Phillips
    Austin Phillips almost 11 years
    @user95711 On my machine at least, pidof will not pick up xyzabc.sh if pidof -x abc.sh is run. If you want safe, you need a system wide lock resource which is why people are suggesting to use a PID file or unique directory name. Using the names in the process list isn't a good way to categorically check whether a process is running since the names can be spoofed.
  • Austin Phillips
    Austin Phillips almost 9 years
    @Pureferret See the Special Parameters section of the bash man page which states $ Expands to the process ID of the shell. In a () subshell, it expands to the process ID of the current shell, not the subshell.
  • swdev
    swdev over 7 years
    pidof doesn't appear to be a standard tool. It is not available in my version of RedHat.
  • Mike Q
    Mike Q almost 6 years
    This works but it leaves one in the position of not knowing if the process is actually running or not if it were to crash (potentially) ?
  • glenn jackman
    glenn jackman almost 6 years
    @MikeQ there's lots of additional steps we can do. Such as writing a pidfile in the directory, and if we can't create the dir because it exists, then verify the pid in the pidfile actually corresponds to a running instance of the program.
  • Mike Q
    Mike Q almost 6 years
    This was the only one that really worked for me, you have to jump through some start hoops (how you call the script) for the other methods and using a lock file makes it so when it crashes it won't start again due to the lock being there.
  • Mike Q
    Mike Q almost 6 years
    Yeah, I briefly thought of that but wasn't sure how well it would work, I'm trying to get this to work for my script that checks vhosts domains and found the 'pgrep -f' mentioned (in another post) the best option so far.
  • frederickjh
    frederickjh almost 6 years
    The update example code could be made more transportable by swapping the two instances of abc.sh with $0, so that no matter what bash script you drop it in it would know its own name.
  • johnbaltis
    johnbaltis about 5 years
    This is the only solution that I found that works on Mac OS X.
  • Suuuehgi
    Suuuehgi over 4 years
    @frederickjh Alternatively $(basename $0): for pid in $(pidof -x $(basename $0)); do
  • Tiana
    Tiana over 4 years
    You can't trap a KILL.
  • gomfy
    gomfy about 4 years
    pidof -x failed for me on bash scripts, this however works seamlessly.
  • imrek
    imrek over 3 years
    If the script is started via a link, this won't work.
  • imrek
    imrek over 3 years
    As @Suuuehgi ponts out, basename should be used, because a script may be run from any directory, but $0 will be whatever path was specified, e.g. if abc.sh is in ~/programs/scripts, running it first from that folder via ./abc.sh and then again from programs via scripts/abc.sh, and a 3rd instance from ~ via programs/scripts/abc.sh, and so on..., will produce as many instances as many paths to the script you can come up with.
  • tukusejssirs
    tukusejssirs over 3 years
    I tried this answer (the snippet), however, for some reasons, exiting the second instance exits the first instance too. Note that I need to match script name including all arguments, therefore I used pgrep instead.
  • ChaosSpeeder
    ChaosSpeeder over 3 years
    This is the best solution. Can't understand, why this isn' not valued with likes.
  • Stavros Korokithakis
    Stavros Korokithakis about 3 years
    Hmm, this doesn't work when I sudo, why is that?
  • Pat
    Pat about 3 years
    You could also use the special pid %PPID. From the pidof man page: The special pid %PPID can be used to name the parent process of the pidof program, in other words the calling shell or shell script.
  • drgibbon
    drgibbon about 3 years
    This seems the cleanest answer to me.
  • Vaibhav S
    Vaibhav S over 2 years
    For /system/bin/sh, (Android default SHELL) I had to modify it using "-o $$", so my code looked like this if pidof -o $$ -x "$0" > /dev/null; then echo "Process already running"; fi Not sure why "-o %PPID" didn't work for me to exclude my script.
  • dokaspar
    dokaspar over 2 years
    I used this solution to ensure that a cron job does not start a script if it is already running. Unfortunately, if somebody has the script open in vi, the condition also prevents another execution of the script ;-)
  • DAB
    DAB about 2 years
    Thanks, IMHO this is the neatest and most portable version
  • yankee
    yankee about 2 years
    This can be simplified by using the -o option: if pidof -x -o $$ "${BASH_SOURCE[0]}"; then echo "Already running."; exit; fi
  • StevieD
    StevieD about 2 years
    doesn't seem to work for me on mac os running from zsh prompt
  • StevieD
    StevieD about 2 years
    no pidof command on macos
  • franzisk
    franzisk almost 2 years
    no mention of macos in the question