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