9

I want to kill the background process belonging to a shell script that I am going to run again.

That means before executing the shell script I want to delete the background process running for the same script.

Thomas Dickey
  • 76,765
Abin
  • 91
  • Did you mean you want to kill all the child processes started by the shell script before you run it again? – Sreeraj Jul 01 '15 at 10:55
  • Please [edit] your question and give us a simple example we can reproduce. What process? The script itself? Something the script launches? How is it launched? – terdon Jul 01 '15 at 11:04
  • Killing the competitors is incredibly hostile. Just exit with an error message and leave the other guy running. – tripleee Oct 06 '19 at 13:37
  • 2
    All of the answers here suggest kill -9 which should never be used routinely. Instead, send the default signal; this allows the victim to perform any required cleanup before proceeding to do an orderly shutdown. – tripleee Oct 06 '19 at 13:39
  • The answer here might be useful to you. – Pourko Nov 06 '20 at 07:11

9 Answers9

15

Check for the existence of a PID from the same script.

add this at the beginning of the script:

#!/bin/bash
script_name=${BASH_SOURCE[0]}
for pid in $(pidof -x $script_name); do
    if [ $pid != $$ ]; then
        kill -9 $pid
    fi 
done
Wis
  • 213
jcbermu
  • 4,736
  • 18
  • 26
  • Good, though kill -9 is usually overkill(!), and can lead to system instability. https://unix.stackexchange.com/questions/8916/when-should-i-not-kill-9-a-process – drkvogel May 14 '22 at 12:38
2
kill -9 $(pgrep -f ${BASH_SOURCE[0]} | grep -v $$)

Very simple.
Uses pgrep to search for all instances of the currently running script.

pgrep is nice since it only returns pids.

Then grep out the currently running pid using $$, so it won't suicide.

Finally kill -9 terminates the previous instances.

1

I did this a long time back in one of my shell scripts. Here is how I did it:

ps aux | \
grep -P ${BASH_SOURCE[0]} | \
grep -v $$ | \
grep -P "bash" | \
grep -oP "^[[:alnum:]]+\s+\d+\s" | \
grep -oP "\d+" | \
xargs kill -9

The beauty of this method is that it will NOT kill the current running script itself, only the previous instances of it.

A sample script to demonstrate the above method is this:

#!/bin/bash

ps aux | grep -P ${BASH_SOURCE[0]} | grep -v $$ | grep -P "bash" | grep -oP "^[[:alnum:]]+\s+\d+\s" | grep -oP "\d+"

sleep 100

Now, run one instance of this script in your terminal. And then run another instance in a different terminal. You will see that the previous instance will be immediately killed while the second one runs fine.

shivams
  • 4,565
1

kill -9 $(pgrep -f ${BASH_SOURCE[0]} | grep -v $$)

Very simple. Uses pgrep to search for all instances of the currently running script. pgrep is nice since it only returns pids. Then grep out the currently running pid, so it won't suicide. Finally kill -9 terminates the previous instances.

1

You can use $0 instead of ${BASH_SOURCE[0]}.

I had to use pgrep -f <filename> instead of pidof -x <filename> because for some reason the latter wasn't returning anything.

Also, kill -9 isn't needed here.

So the result (inspired by @jcbermy's answer):

#!/bin/bash
for pid in $(pgrep -f $0); do
    if [ $pid != $$ ]; then
        kill $pid
    fi 
done
Drarig29
  • 111
0

Try this:

#!/bin/sh
if [ -f /var/run/sh.pid ]; then
    echo "Process already running."
     kill -9 `cat /var/run/sh.pid`
     rm -f /var/run/sh.pid
fi
echo `pidof $$` > /var/run/sh.pid

 # From here, your normal shell script can resume
SHW
  • 14,786
  • 14
  • 66
  • 101
  • This method will kill the script itself, besides killing its previous instances. OP wants to kill only the previous instances. – shivams Jul 01 '15 at 11:10
0

this one is shorter and worked for me in my ruby app

ps -ef| grep search_pattern | awk '{print $2}' | xargs kill -9

replace search_pattern with the name of your script

0
command=$(ps -p $$ -o args --no-headers)
kill -9 $(pgrep -fx "$command" | grep -v $$) || true # kill processes with command, except own process

Most answers use ${BASH_SOURCE[0]}, which is only the path of the script. Not the entire command. For me, it was killing too much, e.g. the editor editing the script.

You get the entire command of the current process with ps -p $$ -o args --no-headers. With pgrep -fx you can exactly match (-x) the full command (-f) and return all process ids. grep -v $$ removes the process id of the current process. kill -9 kills those processes. If there is no process to be killed, don't fail by adding || true.

0

Solution which also take into considerations Process descendants and works with cron

# Current PGID
pgid_current=$(ps -o pgid= $$ | tr -d ' ')

Kill all other PGID's

for pid in $(pgrep -f $0); do pgid=$(ps -o pgid= "${pid}" | tr -d ' ') if [[ -n "${pgid}" && "${pgid}" != "${pgid_current}" ]]; then

log &quot;Kill pgid ${pgid}&quot;

kill -15 -&quot;${pgid}&quot;

fi done

  1. Find current execution PGID - ps -o pgid= $$
  2. Find all PID's based on the executed script name - pgrep -f $0
  3. Find all PGID's of the found PID's - ps -o pgid= "${pid}"
  4. Check if found PGID is not empty - -n "${pgid}" (already killed) and not equal to the current execution PGID - != "${pgid_current}"
  5. Kill all remained PGID's by sending SIGTERM - kill -<signal> -<PGID>

And details usefully for testing and understanding

test.sh
#!/bin/bash

Show last processes

echo ps xao pid,ppid,pgid,sid,user,group,start_time,comm,args | (head -n1 && tail -n10)

Current execution

echo echo "Script Name: $0" echo "Script PID: $$" echo "Script PID pgrep: pgrep -d ' ' -f $0" echo "Script PPID: $PPID" echo "Script PPID via ps: ps -o ppid= $$ | tr -d ' '" echo "Script SID via ps: ps -o sid= $$ | tr -d ' '" echo

crontab -l
*/1 * * * * bash /opt/test.sh >>/opt/cron.log 2>&1
tail -f /opt/cron.log
    PID    PPID    PGID     SID USER     GROUP    START COMMAND         COMMAND
  1176    1175    1176    1175 root     root     10:02 bash            /bin/bash
  1297       2       0       0 root     root     10:06 kworker/0:0-cgr [kworker/0:0-cgroup_destroy]
  1299       2       0       0 root     root     10:07 kworker/u4:0-fl [kworker/u4:0-flush-259:0]
  1543       2       0       0 root     root     10:15 kworker/1:2-mm_ [kworker/1:2-mm_percpu_wq]
  1658       2       0       0 root     root     10:21 kworker/u4:1-ev [kworker/u4:1-events_power_efficient]
  3191     437     437     437 root     root     11:21 cron            /usr/sbin/CRON -f -P
  3192    3191    3192    3192 root     root     11:21 sh              /bin/sh -c bash /opt/test.sh 2>&1 >>/opt/cron.log
  3193    3192    3192    3192 root     root     11:21 bash            bash /opt/test.sh
  3194    3193    3192    3192 root     root     11:21 ps              ps xao pid,ppid,pgid,sid,user,group,start_time,comm,args
  3195    3193    3192    3192 root     root     11:21 bash            bash /opt/test.sh

Script Name: /opt/test.sh Script PID: 3193 Script PID pgrep: 3192 3193 Script PPID: 3192 Script PPID via ps: 3192 Script PGID via ps: 3192 Script SID via ps: 3192

Execution order - PID < PPID > PGID
Cron: 3191 < 437 > 437
  --> sh: 3192 < 3191 > 3192
        --> bash: 3193 < 3192 > 3192
              --> ps: 3194 < 3193 > 3192

cron (3191) --> sh (3192) --> bash (3193) --> ps (3194) \ ____ ____ / __________ / \ / | sh (3192)

Slava
  • 101