11

When I type the following in my terminal running zsh (each line is a command)

babel www/scripts6/lib/data.js > www/scripts/lib/data.js &
babel www/scripts6/lib/user.js > www/scripts/lib/user.js &
babel www/scripts6/lib/profile.js > www/scripts/lib/profile.js &
babel www/scripts6/lib/d3-and-svg.js > www/scripts/lib/d3-and-svg.js &
babel www/scripts6/main.js > www/scripts/main.js &
while [[ $(jobs) =~ 'babel' ]]; do echo 'moo'; done

it moos for about 3 seconds and then stops. But when I put the same exact code in the file moo.zsh and then run it in my terminal with

zsh moo.zsh

it completes in less than 1 second and doesn't moo at all. Why did it happen?

5
  • moo moo moo moo
    – mareoraft
    Commented Sep 4, 2015 at 0:21
  • 2
    shells only tend to have job control turned on in interactive mode. Commented Sep 4, 2015 at 0:32
  • 2
    you should do the waiting with wait Commented Sep 4, 2015 at 0:33
  • @PSkocik make that an answer, it's correct. wait is the proper way to do this and will work both interactively and in a script.
    – Celada
    Commented Sep 4, 2015 at 1:21
  • @PSkocik Is there an easy way to turn job control on and off?
    – mareoraft
    Commented Sep 4, 2015 at 1:49

1 Answer 1

13

In non-interactive shell, you don't have full jobs control. When you start jobs in command substitution, it ran in a subshell. In this subshell, there's no jobs running, you got nothing.

In interactive shell, the MONITOR was set, gave you full jobs control. In this case, zsh store all jobs in a table when you enter a subshell, and will use that job table if there's no jobs in subshell.

With zsh 4.3 and above, you can turn on job control in non-interactive shell by putting -m on shebang line:

#!/usr/bin/zsh -m

or using setopt:

setopt monitor
: The rest of script goes here

A better way to check the job state can be:

#!/usr/bin/zsh
zmodload zsh/parameter

babel www/scripts6/lib/data.js > www/scripts/lib/data.js &
babel www/scripts6/lib/user.js > www/scripts/lib/user.js &
babel www/scripts6/lib/profile.js > www/scripts/lib/profile.js &
babel www/scripts6/lib/d3-and-svg.js > www/scripts/lib/d3-and-svg.js &
babel www/scripts6/main.js > www/scripts/main.js &

while (( ${#jobstates} )); do
  print "moo"
done

Anyway, you can wait for all child processes with builtin wait:

babel www/scripts6/lib/data.js > www/scripts/lib/data.js &
babel www/scripts6/lib/user.js > www/scripts/lib/user.js &
babel www/scripts6/lib/profile.js > www/scripts/lib/profile.js &
babel www/scripts6/lib/d3-and-svg.js > www/scripts/lib/d3-and-svg.js &
babel www/scripts6/main.js > www/scripts/main.js &
# Wait for all children
wait
echo END
3
  • Thank you, but the real question is about the absence of 'moo's. The accepted answer must correctly account for such phenomenon.
    – mareoraft
    Commented Sep 4, 2015 at 1:47
  • @mareoraft: I made it more details.
    – cuonglm
    Commented Sep 4, 2015 at 2:32
  • A big MOO to you sir!!!
    – mareoraft
    Commented Sep 4, 2015 at 20:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .