[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: process substitution and wait()

From: Chet Ramey
Subject: Re: process substitution and wait()
Date: Fri, 12 Apr 2019 12:05:24 -0400
User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:60.0) Gecko/20100101 Thunderbird/60.6.1

On 4/11/19 6:03 PM, Daniel Kahn Gillmor wrote:

>>>>> https://bugs.debian.org/920455
>>>> It wouldn't really affect that. The reason `wait' waits for process
>>>> substitution processes is that they set $!, making them "known to the
>>>> shell" and subject to wait without arguments.
>>>> http://pubs.opengroup.org/onlinepubs/9699919799/utilities/wait.html#tag_20_153
>>> This behavior is actually different between bash 4.4.18 and 5.0, but i
>>> think this is a separate discussion, so i'll defer it to a different
>>> thread to avoid confusion here :) 
>> Yes. It was reported as a bug against bash-4.3, back in 2015, and I agreed
>> with it, so the behavior changed.
>> http://lists.gnu.org/archive/html/bug-bash/2015-03/msg00076.html
> I understand why you made the change, i think.  I'm just observing that
> the change that was made has an observable impact on any child process
> that happens to be bash.
> here's bash 5.0 taking 3 seconds to run a command that posh and zsh and
> dash all run in 0 seconds:
> $ for x in posh dash zsh bash; do printf 'shell: %s\n' "$x"; time -p dash -c 
> "exec $x -c wait" 2> >(sleep 3); done
> shell: posh
> real 0.03
> user 0.00
> sys 0.00
> shell: dash
> real 0.00
> user 0.00
> sys 0.00
> shell: zsh
> real 0.00
> user 0.00
> sys 0.00
> shell: bash
> real 3.00
> user 0.00
> sys 0.00
> $
> Note that the subshell does no process subsitution whatsoever -- the
> process substitution is all happening in the outer loop.

But the execs mean that the shell that is eventually invoked to run the
`wait' is the parent of the process substitution. So the subshell has
children, whether or not it has run the process substitution itself.

Then the question becomes whether wait without arguments should wait for
all children of the shell, or whether it should only wait for those
children it knows it has started.

I can change the code to wait for just the process substitution processes
the current shell has started and "are known to the invoking shell". The
difference between this code and bash-4.4 is that bash-4.4, of course,
didn't try to wait for process substitution processes at all, and didn't
care about children that weren't attached to a job (e.g., coprocs). (That
in itself generated some complaints.)

> Why are the process substitutions children of the spawned process and
> not children of the parent bash shell itself? 

When running a command that is not a builtin or shell function,
redirections happen in the child process. So in the above loop, the process
substitution (which is the `word' attached to the output redirection),
happens in a child of the shell running the loop. The `time' doesn't affect
this at all -- it's a command modifier, not an actual builtin.

The parent shell forks to run dash, and that process (say it's pid 1234)
executes the process substitution, performs the output redirection, and
execs dash. Dash (process 1234) looks at its arguments, finds -c, and
execs `bash -c wait'. The bash (process 1234) executes wait without
arguments, and waits for all of its children.

> As someone who writes bash
> scripts that use the wait builtin, it's a little distressing to me that
> their behavior changes based on whether they are exec()ed in a process
> that already has children or not.

Should wait without arguments wait for all children of the current shell
process? Or should it allow them to become orphaned?

``The lyf so short, the craft so long to lerne.'' - Chaucer
                 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU    address@hidden    http://tiswww.cwru.edu/~chet/

Attachment: signature.asc
Description: OpenPGP digital signature

reply via email to

[Prev in Thread] Current Thread [Next in Thread]