On 11/03/20 06:31, Stephane Chazelas wrote:
IMO,

the best and only reasonable way to address it is to specify
what all shells do: return works like exit when called in a
subshell.

But behaving like 'exit' is not the same as exiting the function and
resuming at the next command, which is clearly stated as a requirement,
albeit difficult to interpret, by the standard.
In

f() (
   foo || return
   bar
)

that return should be guaranteed to exit the function (with
foo's exit status) if foo fails.

And without calling bar, as the name of the 'return' utility implies.

It's also important to keep the guarantee that nothing you do in
a subshell should affect the parent shell (except of course
explicit process killing or poweroff or other pathological
cases). ...

This guarantee (as often) doesn't have such extensive coverage:

"2.9.4 ... ( compound-list ) ...Variable assignments and built-in
commands that affect the environment shall not remain in effect after
the list finishes."

"2.12 ... A shell execution environment consists of the following:
[ a list of things not affected by 'return' that are preserved in the
parent shell ]"

So there's no restriction on 'return' from a subshell that I can find,
absent additional wording in 2.14.

I don't think many would expect that in:

f() {
   return | cat
   echo "$(return)"
   return &
   (return)
   echo done
}
any of those returns would return from the function. I don't see
it desirable that it does. I'm ok for the first one to be left
unspecified but only on the ground that POSIX currently leaves
it unspecified which component of a pipeline may not be run in a
subshell environment (though in practice, shells run either all
components in subshells or only the rightmost one).

"2.12 ... each command of a multi-command pipeline is in a subshell
environment; as an extension [whatever that means], however, any or all
commands in a pipeline may be executed in the current environment..."

So the portable script author has to assume that "all commands" in a
pipeline are run in subshells.

Leaving aside the rationale for each usage, from reading the standard I
would expect all of these examples to return from the function, except
the asynchronous case because its weirdness breaks the necessary
suspension of disbelief.

I suggest that what a script author would prefer is that at least
"return | cat" and "(return)" cause the function to exit without
printing "done", and the other cases to behave like 'exit' on the
principle of "do what I mean".

And on 11/03/20 09:43, Stephane Chazelas wrote:
> On 2020-03-11 15:38:10 +0700, Robert Elz:
>...>
>>
So, it looks as if we could define that return in a subshell in a function
causes the subshell to exit - that said, I'm not sure that there is a lot
of need, it is a confusing usage, and does the same as exit does, so it
is probably better for users to simply use exit instead.
> [...]
>
> But coding patterns like:
>
> f() (
>    foo || return
>    ...
> )
>
> are common.
>
> If only for that, I think POSIX should require "return" to
> behave like exit in that case.

Agreed that this is a common pattern, but wouldn't people be unhappy if
calling f() with failing foo caused the calling script to exit when they
expected it just to return from the function? I know I would be.

> ...

And finally on 11/03/20 06:37, Stephane Chazelas wrote:
>...>
>
> All the ones I tried output 42 and only 42 in
>
> sh -c 'f() { (return 42; echo x); echo "$?"; }; f'

This example is overloaded: is 42 a H2G2 reference, or to the other
memorable event of 1978 (+42=2020)?

"S. R. Bourne, UNIX Time-Sharing System: The UNIX Shell, Bell System
Technical Journal, Volume 57 number 6, July-August 1978"

But SRB, perhaps prudently, omitted functions from his shell: they had
arrived by System V. The paper apparently listed the {} and ()
command-list syntaxes without defining them; you just can't get the
referees.

/df

--
London SW6
UK

Reply via email to