Comment by chubot

8 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...