Date: Fri, 19 May 2023 12:03:51 -0400 From: Chet Ramey <chet.ra...@case.edu> Message-ID: <0a85095a-1665-d936-b4fa-118dd158e...@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. | 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