Why does 'jobs' return pid that already terminated?

Viewed 53

I'm playing with job management in bash, and am seeing confusing behavior.

Here is a minimal script to demonstrate:

#!/bin/bash
set -e

function start_job {
    echo "Kicking off job that sleeps for ${1}"
    sleep "${1}" && echo "Slept for ${1}!" &
}

# Start some jobs - print current child pids.
echo "Jobs are: $(jobs -p)"
start_job 5
echo "Jobs are: $(jobs -p)"
start_job 6
echo "Jobs are: $(jobs -p)"
start_job 7
echo "Jobs are: $(jobs -p)"

# Wait long enough for all children to finish.
echo "Main thread sleeping for 10 and killing all remaining jobs."
sleep 10
echo "Killing sub-jobs."
echo "Jobs are: $(jobs -p)"
kill $(jobs -p)

We create a bunch of child jobs (sleep and report back).

Then we wait for all them them to have a chance to terminate.

Then we invoke jobs -p and kill any pid it returns.

If I change things so my last sleep is 5 seconds, it correctly identifies the 2 remaining pids and kills them.

But if I run it as-is (sleep until they ALL finish), I get the following output:

Jobs are: 
Kicking off job that sleeps for 5
Jobs are: 3352412
Kicking off job that sleeps for 6
Jobs are: 3352412
3352415
Kicking off job that sleeps for 7
Jobs are: 3352412
3352415
3352418
Main thread sleeping for 10 and killing all remaining jobs.
Slept for 5!
Slept for 6!
Slept for 7!
Killing sub-jobs.
Jobs are: 3352418
./mini_job_test.sh: line 23: kill: (3352418) - No such process

This seems totally broken. That 3352418 corresponds to the Slept for 7 job, which, as kill correctly reports back, is a pid that doesn't exist. What gives?

EDIT

Looks like I can specify -r for running jobs and -s for stopped jobs, and with -r, it seems to behave.

... but then I'd expect the funky pid to be stopped... but if I do -s, then that doesn't show up... so:

  • jobs -p: returns that last pid
  • jobs -pr: returns no pids
  • jobs -ps: returns no pids <-- shouldn't it at least show up here if jobs -p is returning a non-running pid???
0 Answers
Related