15

So, I have some jobs like this:

sleep 30 | sleep 30 &

The natural way to think would be:

kill `jobs -p`

But that kills only the first sleep but not the second.

Doing this kills both processes:

kill %1

But that only kills at most one job if there are a lot of such jobs running.

It shouldn't kill processes with the same name but not run in this shell.

2
  • killall sleep
    – DopeGhoti
    Aug 2, 2017 at 17:20
  • What do you do after running sleep 30 | sleep 30? Do you press Control-z and do bg? Aug 2, 2017 at 17:31

5 Answers 5

11

A somewhat shorter version of xhienne's answer, but not pure-bash:

jobs -p | xargs -I{} kill -- -{}
4
  • "not pure-bash"; which part is not bash? Apr 3, 2020 at 15:12
  • 3
    xargs is not part of bash. It's part of findutils.
    – sduthil
    Apr 6, 2020 at 13:01
  • If brevity is desired, then I believe this is equivalent to jobs -p | xargs -i kill -- -{} Jan 17 at 4:12
  • True, although -i is documented as deprecated.
    – sduthil
    Jan 19 at 20:12
7

Use this:

pids=( $(jobs -p) )
[ -n "$pids" ] && kill -- "${pids[@]/#/-}"

jobs -p prints the PID of process group leaders. By providing a negative PID to kill, we kill all the processes belonging to that process group (man 2 kill). "${pids[@]/#/-}" just negates each PID stored in array pids.

5
  • I couldn't get this to work in Ubu 20.04. (kill complained about negitave PID numnbers.). However, this works: while [ -n "$(jobs -p)" ]; do kill %%; done
    – jpaugh
    Mar 1, 2021 at 5:39
  • @jpaugh I don't have U20.4. What you describe would be a bug to report to Bash, since negative PIDs are a property of the kill(2) system call and are part of the POSIX standard. Are you sure you copied-pasted my code correctly? What is your version of Bash? You can adapt my code to /bin/kill if Bash's kill is buggy (but IMO this is very unlikely).
    – xhienne
    Mar 1, 2021 at 10:23
  • I tried both kill and /usr/bin/kill; While I may have gotten the code wrong, I did verify the format of the PIDs before passing them to kill. I'm not going to look into this further, but hopefully this convo will help someone else.
    – jpaugh
    Mar 2, 2021 at 17:31
  • For the reference, can you please add here the error messages produced by both Bash's builtin kill and /bin/kill when given a (valid) negative PID number? (/usr/bin/kill is surprising, you probably mean /bin/kill)
    – xhienne
    Mar 2, 2021 at 18:06
  • No, I used /usr/bin/kill. It's probably a symlink to /bin/kill (Ubuntu). I'll try to remember to re-run it when I'm in front of a linux box.
    – jpaugh
    Mar 2, 2021 at 20:15
3

Use kill $( jobs -p )... I love it. Use this if you’ve jost got too many jobs for kill’s argv (it can happen I guess):

killalljobs() { for pid in $( jobs -p ); do kill -9 $pid ; done ; }

11
  • 2
    or simply use pkill -s0 as shown here
    – user313992
    Jan 31, 2019 at 23:16
  • @mosvy But what about less feature-rich environments, where no pkill/pgrep pair exists?
    – user2497
    Jan 31, 2019 at 23:22
  • there you'll have to do it by hand ;-)
    – user313992
    Jan 31, 2019 at 23:36
  • 2
    Notice that kill $(jobs -p) will only kill process leaders ie. it won't kill the sleep in (sleep 3600 &) or (sleep 3600; true) &. That may or may not be what you want. Also busybox has pgrep but no pkill, so kill $(pgrep -s0).
    – user313992
    Jan 31, 2019 at 23:44
  • 1
    any interactive shell -- the standard requires that any interactive shell ignore the SIGQUIT and SIGTERM signals.
    – user313992
    Feb 27, 2019 at 8:27
2

You can use pkill and pgrep to kill a list of process names.

From the man page:

pgrep looks through the currently running processes and lists the process IDs which matches the selection criteria to stdout. All the criteria have to match. For example, pgrep -u root sshd will only list the processes called sshd AND owned by root. On the other hand, pgrep -u root,daemon will list the processes owned by root OR daemon. pkill will send the specified signal (by default SIGTERM) to each process instead of listing them on stdout.

An example using pgrep, pkill,

$ pgrep -l script.sh
12406 script.sh
12425 script.sh

$ pkill $(pgrep script.sh)

$ cat signal-log
Name: ./script.sh Pid: 12406 Signal Received: SIGTERM
Name: ./script.sh Pid: 12425 Signal Received: SIGTERM
2

This will kill all jobs, most recently created first:

while kill %%; do :; done

This stops when there are no more jobs to kill, and prints:

bash: kill: %%: no such job

Works in zsh too.

3
  • Or more exactly, it works only in zsh, not sh or bash.
    – user23013
    Sep 28, 2019 at 23:06
  • Combined with the accepted answer, this becomes while [ -n "$(jobs -p)" ]; do kill %%; done. Prob slower, but no extraneous error message.
    – jpaugh
    Mar 1, 2021 at 5:41
  • Works fine for me with bash 4.4.20.
    – href_
    Aug 18, 2022 at 13:15

You must log in to answer this question.

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