bug-bash
[Top][All Lists]
Advanced

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

Re: nofork command substitution


From: alex xmb ratchev
Subject: Re: nofork command substitution
Date: Fri, 19 May 2023 21:03:17 +0200

On Fri, May 19, 2023, 20:43 Robert Elz <kre@munnari.oz.au> wrote:

>     Date:        Fri, 19 May 2023 12:03:51 -0400
>     From:        Chet Ramey <chet.ramey@case.edu>
>     Message-ID:  <0a85095a-1665-d936-b4fa-118dd158e5a8@case.edu>
>
>
>   | Maybe, and certainly possible, but a more likely use is just a simple
>   | assignment to REPLY.
>
> In such cases, the value to be assigned needs to come from somewhere,
> and I can't really see a lot of benefit in using this indirect method
> of getting that value, rather that simply putting the somewhere directly
> in the word, instead of this command substitution, except in the most
> unlikely of cases (like when REPLY is built up gradually, via a loop
> gradually adding more text).
>
>   | I envision a little more complexity than that; a ${| printf -v REPLY
> ...; }
>   | doesn't really require the command substitution at all.
>
> Nor does a simple assignment to REPLY
>
>   | Probably. The bash implementation is the union of mksh and ksh93's
> (with
>   | one exception, see below), and that part comes from mksh.
>
> Ah, that info wasn't apparent earlier - I wasn't aware this was just
> a copy of earlier implementations, it seemed more like something new.
>
>   | The other benefit is not to have to output any text if you don't have
> to,
>   | and for the calling shell not to have to read it.
>
> That's all pseudo-noise --- the shell would need to set REPLY, and then
> expand its value.  The alternative is simply to "write" the output into
> a buffer in memory which the shell then "reads" when it wants the results
> of the command substitution.  Those two are really no different, except
> that the REPLY form does all of the work needed to assign to a var, and
> then access it (one way or another) - plus everything necessary to make
> REPLY a local variable.
>
> Of course all of this only works simply if the commands in the cmdsub
> generating the text are built in to the shell, if something like sed
> is being used (or awk) then you have to read its output anyway.
>
>   | I would have thought it obvious the space, tab, and newline variants do
>   | the execute-command-in-the-current-environment-and-capture-output
> thing,
>   | as described first, where the exceptions are explicitly detailed and
>   | everything else is invalid. I can make the former even more explicit.
>
> The question is more (aside from "compat with mksh" which I didn't
> previously
> know was an aim - not sure 100% compat needs to be anyway) why 3 different
> but equivalent forms are useful.   The space variant is obvious, that's how
> we get this to be a cmdsub rather than a var expansion.   I can see the use
> of the newline form, so one can write
>
>         cmd arg arg word${
>                 sed -n /^p/p /usr/dict/words
>                         }more
>
> or something, without needing to put a hard to see space after the '{'.
>
> I can't however see any real rational purpose for the tab variant.
>

tab is a general separator
as this is a separators list


  | I decided not to seek deliberate incompatibility with mksh.
>
> Sure, that makes sense, but you don't need to necessarily implement
> everything they implemented, when there is no need for it.
>
>   | Remember where I said this was the union of the mksh and ksh93
> features?
>   | This one is from ksh93. It's not really any different from $(...). It
>   | doesn't cost anything additional to support, either.
>
> It might not cost anything to implement, but it needs to be explained,
> documented, and then users forever need to try and understand why there
> are two (seemingly equivalent) ways to achieve the same thing, and try
> to work out which of them is the right one to use.
>
> Introducing complexity, no matter how cost free it is to implement, is
> rarely cost free in reality.
>
>   | You can have that, if you want. x=${ func; } (or x=${ func 1 2 3; })
> does
>   | the right thing. The ${...;} inherits the positional parameters, so
> things
>   | like `shift' work as expected in the body,
>
> I'm not sure I'd call what happens there "as expected" - I'd just call
> it weird.
>
> There's also the issue of in exactly what context these expansions happen.
> For words that are the command name, or args, that's fairly simple, the
> expansions occur in the context of the parent shell (the one running the
> script or whatever).   But for expansions in redirects, as in
>
>         >${ shift 3; echo $2 ;}
>
> or something, then redirects occur in the context of the command about
> to be executed (ie: after the fork) and some shells perform the expansions
> on the redirect word then as well (others perform them in the parent
> shell).
>
> In mksh for example (since I now know I can test this using that):
>
> $ set -- a b /tmp/file
> $ ls >${ shift 2; echo $1; }
> $ echo $1
> a
>
> The output goes to /tmp/file, but $1 has not altered in the parent shell.
> I don't have this code in bash to test, but it appears as if bash will do
> the same.   The NetBSD shell would not, expansions in redirects (but not
> the actual redirections) are performed in the parent shell, so side effects
> in those are just as visible as any other expansions in the command.
>
> [Aside: when I first tried this, I forgot the need for the ';' before the
> '}'
>  but, surprisingly, it still worked exactly the same way, mksh it seems
> simply finds a terminating '}' and uses it - reserved word type matching
> not
> required.]
>
>   | It's to allow local variables and `return'. The existing
> implementations
>   | all agree on that.
>
> Sure, the question isn't that, it is why it doesn't also make local
> positional params, just the same as any other function.   (But return
> and local can both be made to work in any context you like, there's
> nothing that says they are only allowed in a function, or something like
> it, other than any rules you impose upon yourself ... it seems like as
> described, the "${ " form is more like execution of a '.' script, than
> a function.
>
>   | Expansions are performed left-to-right (or, if you prefer, beginning to
>   | end) in the word, and the command substitution modifies the current
>   | execution environment.
>
> Sure, but last time I looked, it was still unspecified just when side
> effects of expansions get applied.
>
>   | There's no reason to be deliberately incompatible.
>
> Sure, understood, but also no reason to implement nonsense, or frills
> which are not needed.  Make what is implemented be compatible, by all
> means, but that does not mean you need to implement everything.
>
> After all mksh doesn't attempt to be compat with bash wrt brace expansion.
> bash does it the sane way (first) - mksh (maybe kshNN as well) the insane
> way (after parameter expansions) - nothing at all compatible there.
>
>   | The only thing I just
>   | couldn't stomach implementing was making `exit' in the body of this
> form
>   | of command substitution act like `return' and not exit the shell, which
>   | ksh93 does.
>
> Fully understand, I wouldn't do that either.
>
>   | Well, that won't do anything since it's in double quotes
>
> Yes, ... those were (probably) just for exposition ... not actually
> intended.
>
> The issues with all of this are more the increased complexity for the user
> trying to work out how it all works, and why.
>
> kre
>
>
>
>


reply via email to

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