0

So I've looked up other questions and answers for this and as you can imagine, there are lots of ways to find this. However, my situation is kind of different.

I'm able to check whether a bash script is already running or not and I want to kill the script if it's already running.

The problem is that with the below code, -since I'm running this within the same script- the script kills itself too because it sees a script already running.

result=`ps aux | grep -i "myscript.sh" | grep -v "grep" | wc -l` if [ $result -ge 1 ] then echo "script is running" else echo "script is not running" fi 

So how can I check if a script is already running besides it's own self and kill itself if there's another instance of the same script is running, else, continue without killing itself.

I thought I could combine the above code with $$ command to find the script's own PID and differentiate them this way but I'm not sure how to do that.

Also a side note, my script can be run multiple times at the same time within the same machine but with different arguments and that's fine. I only need to identify if script is already running with the same arguments.

2
  • 1
    How about using a watchdog kind of file? Make a lock file before kicking off the script and delete it after its successful execution. In between check condition if its present if yes then leave the script from running or kick it off again. Commented Nov 27, 2019 at 10:31
  • 1
    maybe just flock? + lsof to find the pid Commented Nov 27, 2019 at 10:36

2 Answers 2

1
pid=$(pgrep myscript.sh | grep -x -v $$) # filter non-existent pids pid=$(<<<"$pid" xargs -n1 sh -c 'kill -0 "$1" 2>/dev/null && echo "$1"' --) if [ -n "$pid" ]; then echo "Other script is running with pid $pid" echo "Killing him!" kill $pid fi 

pgrep lists the pids that match the name myscript.sh. From the list we filter current $$ shell with grep -v. It the result is non-empty, then you could kill the other pid.

Without the xargs, it would work, but the pgrep myscript.sh will pick up the temporary pid created for command substitution or the pipe. So the pid will never be empty and the kill will always execute complaining about the non-existent process. To do that, for each pid in pids, I check if the pid exists with kill -0. If it does, then it is outputted, effectively filtering all nonexistent pids.

You could also use a normal for loop to filter the pids:

# filter non-existent pids pid=$( for i in $pid; do if kill -0 "$i" 2>/dev/null; then echo "$i" fi done ) 

Alternatively, you could use flock to lock the file and use lsof to list current open files with filtering the current one. As it is now, I think it will kill also editors that are editing the file and such. I believe the lsof output could be better filtered to accommodate this.

if [ "${FLOCKER}" != "$0" ]; then pids=$(lsof -p "^$$" -- ./myscript.sh | awk 'NR>1{print $2}') if [ -n "$pids" ]; then echo "Other processes with $(echo $pids) found. Killing them" kill $pids fi exec env FLOCKER="$0" flock -en "$0" "$0" "$@" fi 
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you. First option seems convenient. Although, it's killing the previously running script. Instead, it should kill itself, not the previous script.
It is also not differentiating the arguments. If I run a script with some argument like myscript.sh arg1 and then run it again with different argument like myscript.sh arg2 it still says "Other script is running with pid" but it shouldn't do that if the arguments are different.
Then change the pgrep into the common atipattern ps aux | grep ... | grep -v grep, or use ex. soemthing like this, like pgrep -af myscript.sh and compare arguments, etc.
1

I would go with either of 2 ways to solve this problem.

1st solution: Create a watchdog file lets say a .lck file kind of on a location before starting the script's execution(Make sure we use trap etc commands in case script is aborted so that .lck file should be removed) AND remove it once execution of script is completed successfully.

Example script for 1st solution: This is just an example a test one. We need to take care of interruptions in the script, lets say script got interrupted by a command or etc then we could use trap in it too, since at that time it would have not been completed but you may need to kick it off again(since last time it was not completed).

cat file.ksh #!/bin/bash PWD=`pwd` watchdog_file="$PWD/script.lck" if [[ -f "$watchdog_file" ]] then echo "Please wait script is still running, exiting from script now.." exit 1; else touch $watchdog_file fi while true do echo "singh" > test1 done if [[ -f "$watchdog_file" ]] then rm "$watchdog_file" fi 

2nd solution: Take pid of current running shell using $$ save it in a file. Then check if that process is still running come out of script if NOT running then move on to run statements in script.

10 Comments

1st solution makes sense. Can you expand it more with examples?
@MarryJane, sure I just came for tea will write in some time.
@MarryJane, I have added a very simple example(it is example of an infinite loop so be aware), for understanding purposes only, cheers. Lemme know in case of any queries here.
Thank you. Though, I'm still not sure how can I include the arguments of the running bash script.
Thank you kind sir! Cheers :)
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.