Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Nofork ${{var}...} edge cases



On Sat, May 31, 2025 at 10:57 AM Bart Schaefer
<schaefer@xxxxxxxxxxxxxxxx> wrote:
>
> On Sat, May 31, 2025 at 12:21 AM Mikael Magnusson <mikachu@xxxxxxxxx> wrote:
> >
> > This just came up on IRC, and I'm not sure what the currently expected
> > result is here, and I couldn't find any test coverage for this either:
> > % REPLY=before; echo $REPLY ${ echo 1} ${| REPLY=2} $REPLY
> > before 1 2 1
> >
> > I find it very surprising that REPLY is overwritten by ${ echo 1}
>
> Not really obvious but you have to have a space between "1" and "}" --
> spaces inside BOTH braces, not just the left one.  Without the final
> space, this is being interpreted as
>   ${{} echo 1}
> which defaults to using $REPLY in the scope of the caller, just as if you wrote
>   ${{REPLY} echo 1}.
> REPLY is chosen there because ${| echo 1} uses REPLY.
>
> ${{} ...} is permitted because ${} is permitted.  Overlooked when
> writing the doc, sorry.
>
> ${ ... } (with the spaces on both ends) actually uses an undocumented
> read-only local ${.zsh.cmdsubst}.
>
> It might be possible to make it a bad substitution to skip the final space.

I would argue that ${ foo} and ${ foo } should behave exactly the
same, but also, I don't see a difference currently.:
% REPLY=before; echo $REPLY ${ echo 1} ${| REPLY=2} $REPLY
before 1 2 1
% REPLY=before; echo $REPLY ${ echo 1 } ${| REPLY=2} $REPLY
before 1 2 1

if ${ echo 1} was interpreted as ${{} echo 1} then it would not expand
to "1", but to the value of REPLY, which is not set in that code
snippet, so I don't think this is what actually happens / goes wrong.
And in fact, we see that it acts differently, echo 1 is output
directly to stdout when actually using a ${{} } construct as expected:
% REPLY=before; echo $REPLY ${{} echo 1} ${| REPLY=2} $REPLY
1
before 2 before


-- 
Mikael Magnusson




Messages sorted by: Reverse Date, Date, Thread, Author