Kill all background jobs

Is there a more compact form of killing background jobs than:

for i in {1..5}; do kill %$i; done

Also, {1..5} obviously has a hard-coded magic number in it, how can I make it “N” with N being the right number, without doing a:

$(jobs | wc -l)

I actually use j in PS1 to get the # of managed jobs, is this equivalent?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

To just kill all background jobs managed by bash, do

kill $(jobs -p)

Note that since both jobs and kill are built into bash, you shouldn’t run into any errors of the Argument list too long type.

Method 2

Use xargs instead of the $(jobs -p) subcommand, because if jobs -p is empty then the kill command will fail.

jobs -p | xargs kill

Method 3

I guess depending on what output jobs -p gives, the solution could be slightly different. In my case

$ jobs -p
[1]  - 96029 running    some job
[2]  + 96111 running    some other job

Therefore, doing the following is no good.

$ jobs -p | xargs kill
kill: illegal process id: [1]

On the other hand, running kill $(jobs -p) does work but entails a lot of error messages, since the non-PID strings get passed to kill as well.

Therefore, my solution is to grep the PID first and then use xargs, as follows:

$ jobs -p | grep -o -E 'sd+s' | xargs kill

Method 4

@pizdelect point is what brought me here. Jobs spawned using pipes have multiple pids. jobs -p is only going to provide the first.

for j in $(jobs | awk '{gsub("[^0-9]","",$1);printf "%%%sn", $1}');do kill $j;done

If you want to get them all, you have to use the job ID.

Method 5

I prefer to check if there’s any jobs that exist before killing them – this way the script won’t fail if there’s nothing running.

It’s also shorter to type. Throw this in your .bash_profile:

function killjobs () {
    JOBS="$(jobs -p)";
    if [ -n "${JOBS}" ]; then;
        kill -KILL ${JOBS};
    fi
}

Then run:

killjobs

To kill any jobs running.

Method 6

In bash and zsh I would use something like this (after considering the comment from pizdelect about the process group):

jobs -p | extract_pids | xargs --no-run-if-empty kill -TERM -- || true

where

extract_pids() {
    awk '{
        if (NF == 1) { print -$1 }
        else if (NF > 1) {
            if ($2 == "+" || $2 == "-") { print -$3 }
            else { print -$2 }
        }
    }'
}

As far as I tested jobs -p returns the PIDs in bash, f.i.:

$ jobs -p
41659

but can have these formats in zsh, f.i.:

$ jobs -p
[1]    206 running    sleep 10
[2]  - 208 running    sleep 10
[3]  + 210 running    sleep 10

extract_pids tries to handle these (4) cases.

Note: checking the processes with jobs -p can return PIDs, which are already gone at the time xargs kill is invoked, so we ignore errors with a trailing || true.

Method 7

I have several backgrounded compound commands I want to terminate gracefully, by sending SIGINT to each process, on macOS. None of the other solutions worked properly for that, so I came up with this:

jobs -p | xargs -n1 pkill -SIGINT -g

jobs -p lists background processes started by the current shell.

xargs -n1 executes pkill once for each job.

pkill -SIGINT -g sends SIGINT (same as ctrl+c) to all processes in the process group.

Method 8

The accepted answer by @jw013 works in most situations, except when a job has background jobs since only the group leader is killed. (@pizdelect identified this limitation in this comment.)

@pizdelect also pointed out that kill accepts negative PID values to choose the whole process group in this comment.

Furthermore, one might not want to kill Stopped jobs, hence jobs -r might be useful.

Combining all these elements, here’s a solution that kills all running jobs, including background jobs:

for i in $(jobs -rp); do kill -- "-$i"; done

Here’s a solution that kills all jobs, including background jobs:

for i in $(jobs -p); do kill -- "-$i"; done

Method 9

Seems like jobs -p | xargs kill does the job, however it produces some unwanted output piped to kill. Here I am grouping output of jobs -p by having/not having + or – character

function killjobs() {
    JOBS=$(jobs -p)
    echo $JOBS | grep -v "+|-"| awk '{print $2}' | xargs kill -9
    echo $JOBS | grep "+|-"| awk '{print $3}' | xargs kill -9
}

And later you can just call killjobs


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x