Comment by chubot
10 hours ago
Yup, job control is a huge mess. I think Bill Joy was able to modify the shell, the syscall interface, and the terminal driver at the same time to implement the hacky mechanism of job control. But a few years later that kind of crosscutting change would have been harder
One thing we learned from implementing job control in https://oils.pub is that the differing pipeline semantics of bash and zsh makes a difference
In bash, the last part of the pipeline is forked (unless shopt -s lastpipe)
In zsh, it isn't
$ bash -c 'echo hi | read x; echo $x' # no output
$ zsh -c 'echo hi | read x; echo $x'
hi
And then that affects this case:
bash$ sleep 5 | read
^Z
[1]+ Stopped sleep 5 | read
zsh$ sleep 5 | read # job control doesn't apply to this case in zsh
^Zzsh: job can't be suspended
So yeah the semantics of shell are not very well specified (which is one reason for OSH and YSH). I recall a bug running an Alpine Linux shell script where this difference matters -- if the last part is NOT forked, then the script doesn't run
I think there was almost a "double bug" -- the script relied on the `read` output being "lost", even though that was likely not the intended behavior
FWIW here is another piece of trivia about job control: the API means you can't spawn a child process "safely" in POSIX -- you have to trust that that the executable you're spawning is well-behaved (or use more advanced Linux process isolation)
In this case it was the Zed editor spawning the zsh shell:
How to Lose Control of your Shell - https://registerspill.thorstenball.com/p/how-to-lose-control...
zsh has a bug where it doesn't do the job control cleanup properly in some cases -- when fork-exec() optimizations happen.
This can mess up the calling process. For example, here you could no longer kill Zed by hitting Ctrl-C, even after zsh is done.
My comment: https://lobste.rs/s/hru0ib/how_lose_control_your_shell#c_dfl...