57

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?

  • 3
    kill $(jobs -p) seems easier. – jw013 Jul 19 '12 at 22:00
  • I would prefer to kill jobs individually, if possible. (I might have misunderstood your comment, though) – Robottinosino Jul 19 '12 at 22:12
  • for pid in $(jobs -p); do kill $pid; done? – jw013 Jul 19 '12 at 22:27
  • 3
    @jw013 It's not only easier, it's actually correct (please post it as an answer), unlike a solution based on counting the lines of the output of jobs which only works if the jobs happen to be numbered consecutively. Oh, and “kill jobs individually” is meaningless: passing multiple PIDs to the kill command does exactly the same thing as passing them separately. – Gilles Jul 19 '12 at 23:52
  • I was entering the command incorrectly, kill $(jobs -p) words and looks very correct to me too. Ready to accept. – Robottinosino Jul 20 '12 at 0:31
95

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.

  • 2
    Also for posterity, what bahamat thinks is the way to do it in zsh disqualifies them as any authority on the topic. – peth Mar 8 '13 at 23:46
  • I feel like I should know this, but how does the '$' work here? – fersarr Jan 8 '15 at 17:21
  • 1
    @fersarr Here you go – jw013 Jan 8 '15 at 21:27
  • @bahamat That doesn't actually work since the PID may be in field 2 or 3 depending on whether the job is one of %+ or %- or not. What works is kill %${(k)^jobdirs}, which is indeed longer; if you need to list the PIDs then you can use the even longer ${${jobstates#*:*:}%%=*}. – Gilles Jan 28 '16 at 10:06
  • On CentOS, my prompt is waiting for more input > – Janac Meena Nov 13 '18 at 19:18
13

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

jobs -p | xargs kill
  • 1
    This has the same exact effect though , it prints the help and exits with code 123 – cat Jun 7 '17 at 20:51
  • 1
    The the command works fine on OSX but doesn't work on Debian – brunocascio Jun 8 '17 at 12:23
  • This works great on CentOS 6 – Janac Meena Nov 13 '18 at 19:19
  • jobs -p | xargs -rn10 kill will do better better if jobs -p does not return any PIDs. Note that -r option is GNU extension. – NarūnasK Feb 1 at 16:27
  • As mentioned above, the -r is the short format for the --no-run-if-empty GNU extension to xargs which instructs it to not run the command if stdin has no data. – Anthony Geoghegan Jun 10 at 11:09
3

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.

1

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.

0

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

0

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 '\s\d+\s' | xargs kill
  • What shell are you using? What does echo $0 show? What does help jobs show? The output illustrated is not POSIX-compliant; any implementation of jobs should have a -p option with the intended behavior. – Wildcard Jul 5 at 22:16
  • Thanks for pointing this out. I am using zsh, and that is the reason for the strange output. I switched to bash and jobs -p did only output PID. I've just learned that zsh is not completely POSIX-compliant. – Fanchen Bao Jul 6 at 2:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.