I don't think the process running `cat' is a sibling of the subshell.

bash performs an optimisation that runs redirections applied to simple
commands that run external programs, or subshell compound commands after
the fork(). (to avoid having to restore file descriptors after running
the command.)

This causes other weird pitfalls, e.g. the following script loops
infinitely, and always runs `sleep 1 > /tmp/file1':

    i=0
    while [ "$i" -lt 10 ]
        do sleep 1 > "/tmp/file$(( ++i ))"
    done

On 23/10/2022, Oğuz İsmail Uysal <oguzismailuy...@gmail.com> wrote:
> To reproduce:
>
>     $ echo $BASH_VERSION
>     5.2.2(3)-release
>     $ ( : & wait ) > >(cat)
>     *hangs*
>
> It should return immediately, but hangs instead.

This behaviour has existed for a while in bash, it was not introduced in
5.2.

It causes many pitfalls that are hard to spot; see [1] (which I just
updated to mention a problematic use case like yours), and [2].

[1]: <https://mywiki.wooledge.org/BashPitfalls#pf64>
[2]: https://www.vidarholen.net/contents/blog/?p=865

I have never encountered a problem like the one you described before,
but that is probably one of the worse pitfalls caused by this
optiomisation. :^)

Effectively, because of the optimisation, your command is run like:

    (exec > >(cat); : & wait)

So the subshell process that runs `cat' is a child of the subshell that
runs `: & wait', so wait will also wait for it.

To inhibit this optimisation, you can wrap your subshell compound
command (or simple command) in a group command, and apply the
redirections to it instead of the subshell command:

    { (: & wait) ;} > >(cat)

Or, in your specific case, use "$!" to only wait for the most recent
background job.

    (: & wait -- "$!") > >(cat)

Cheers.
 emanuele6

Reply via email to