Normally, when a job is launched in the background,
jobs will report that it is finished the first time it is run after the job's completion, and nothing for subsequent executions:
$ ping -c 4 localhost &>/dev/null &  9666 $ jobs + Running ping -c 4 localhost &> /dev/null & $ jobs + Done ping -c 4 localhost &> /dev/null $ jobs ## returns nothing $
However, when run in a subshell within a script it seems to always return a value. This script will never exit:
#!/usr/bin/env bash ping -c 3 localhost &>/dev/null & while [[ -n $(jobs) ]]; do sleep 1; done
If I use
tee in the
[[ ]] construct to see the output of
jobs, I see that it is always printing the
Done ... line. Not only once as I expected but, apparently, for ever.
What is even stranger is that running
jobs within the loop causes it to exit as expected:
#!/usr/bin/env bash ping -c 3 localhost &>/dev/null & while [[ -n $(jobs) ]]; do jobs sleep 1; done
Finally, as pointed out by @mury, the first script works as expected and exits if run from the commandline:
$ ping -c 5 localhost &>/dev/null &  13703 $ while [[ -n $(jobs) ]]; do echo -n . ; sleep 1; done ...+ Done ping -c 5 localhost &> /dev/null $
This came up when I was answering a question on Super User so please don't post answers recommending better ways of doing what that loop does. I can think of a few myself. What I am curious about is
jobsact differently within the
[[ ]]construct? Why will it always return the
Done...line while it doesn't when run manually?
Why does running
jobswithin the loop change the behavior of the script?