How to check if another instance of my shell script is running
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.
Related videos on Youtube
Jatin Bodarya
Updated on June 12, 2021Comments
-
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 fromabc.sh
script only... inside it I have written following statementstatus=`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 almost 11 yearsThe PID of the running process is stored in $$, just ignore it from the list grep -v $$
-
Grzegorz Żur almost 11 yearsIt is simpler to use some lock file. If file is present another copy is running. Just make sure the file is removed.
-
Jatin Bodarya almost 11 yearsIts not safe way to check file in my case..so I suppose to use this way
-
Adam Siemion almost 11 yearsWhat 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 almost 11 yearswrong is I suppose to check from this script only.... so every time It checks its own PID and exits !!!
-
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 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 almost 10 yearspossible duplicate of Quick-and-dirty way to ensure only one instance of a shell script is running at a time
-
-
Jatin Bodarya almost 11 yearsand what if another script "xyzabc.sh" is also running at the same time ? This answer is good but not so safe.
-
Austin Phillips almost 11 years@user95711 On my machine at least,
pidof
will not pick upxyzabc.sh
ifpidof -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 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 over 7 years
pidof
doesn't appear to be a standard tool. It is not available in my version of RedHat. -
Mike Q almost 6 yearsThis 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 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 almost 6 yearsThis 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 almost 6 yearsYeah, 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 almost 6 yearsThe 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 about 5 yearsThis is the only solution that I found that works on Mac OS X.
-
Suuuehgi over 4 years@frederickjh Alternatively
$(basename $0)
:for pid in $(pidof -x $(basename $0)); do
-
Tiana over 4 yearsYou can't trap a KILL.
-
gomfy about 4 years
pidof -x
failed for me on bash scripts, this however works seamlessly. -
imrek over 3 yearsIf the script is started via a link, this won't work.
-
imrek over 3 yearsAs @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. ifabc.sh
is in~/programs/scripts
, running it first from that folder via./abc.sh
and then again fromprograms
viascripts/abc.sh
, and a 3rd instance from ~ viaprograms/scripts/abc.sh
, and so on..., will produce as many instances as many paths to the script you can come up with. -
tukusejssirs over 3 yearsI 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 over 3 yearsThis is the best solution. Can't understand, why this isn' not valued with likes.
-
Stavros Korokithakis about 3 yearsHmm, this doesn't work when I sudo, why is that?
-
Pat about 3 yearsYou 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 about 3 yearsThis seems the cleanest answer to me.
-
Vaibhav S over 2 yearsFor /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 over 2 yearsI 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 about 2 yearsThanks, IMHO this is the neatest and most portable version
-
yankee about 2 yearsThis can be simplified by using the
-o
option:if pidof -x -o $$ "${BASH_SOURCE[0]}"; then echo "Already running."; exit; fi
-
StevieD about 2 yearsdoesn't seem to work for me on mac os running from zsh prompt
-
StevieD about 2 yearsno pidof command on macos
-
franzisk almost 2 yearsno mention of macos in the question