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.

5
  • Did you mean you want to kill all the child processes started by the shell script before you run it again?
    – Sreeraj
    Commented Jul 1, 2015 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
    Commented Jul 1, 2015 at 11:04
  • Killing the competitors is incredibly hostile. Just exit with an error message and leave the other guy running.
    – tripleee
    Commented Oct 6, 2019 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
    Commented Oct 6, 2019 at 13:39
  • The answer here might be useful to you.
    – Pourko
    Commented Nov 6, 2020 at 7:11

9 Answers 9

14

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
1
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.

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
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
1
  • This method will kill the script itself, besides killing its previous instances. OP wants to kill only the previous instances.
    – shivams
    Commented Jul 1, 2015 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

1
  • 1
    grep and awk is redundant; Awk does pattern matching. pgrep would be an even simpler approach...
    – jasonwryan
    Commented Jun 11, 2016 at 6:45
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 "Kill pgid ${pgid}"

    kill -15 -"${pgid}"
  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)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .