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 18:39:50 +0200

On Fri, May 19, 2023, 18:35 alex xmb ratchev <fxmbsw7@gmail.com> wrote:

>
>
> On Fri, May 19, 2023, 18:04 Chet Ramey <chet.ramey@case.edu> wrote:
>
>> On 5/19/23 6:11 AM, Robert Elz wrote:
>> >      Date:        Thu, 18 May 2023 22:14:28 -0400
>> >      From:        "Dale R. Worley" <worley@alum.mit.edu>
>> >      Message-ID:  <874jo9kqyj.fsf@hobgoblin.ariadne.com>
>> >
>> >    | Chet Ramey <chet.ramey@case.edu> writes:
>> >    | > Bash allows the close brace to be joined to the remaining
>> >    | > characters in the word without being followed by a shell
>> metacharacter
>> >    | > as a reserved word would usually require.
>> >    |
>> >    | I had to read this a couple of times to figure out what it means.
>> In
>> >    | particular "the word" isn't well-bound here.  Perhaps better is
>> >
>> > I'm not sure why this is worth mentioning at all, any more than that
>> > more text, that is part of the same word, can follow a ${var} expansion.
>>
>> Because you know someone will eventually ask about it.
>>
>> > These things (variable expansions, command substitutions, arithmetic
>> > expansion, tilde exbansion, and in bash and some other shells, brace
>> > expansion) are all word expansions.   All of them occur anywhere in a
>> > shell "word", and I don't see this proposed new form as being any
>> different.
>>
>> It's not. It's command substitution.
>>
>> > The only oddity is that inside the nofork cmd sub, the closing '}' is
>> being
>> > treated as a reserved word (as it is when used for grouping lists), but
>> from
>> > the outside, it is just a part of the word that contains it.
>>
>> Exactly.
>>
>> >    | My guess is that the intention is for COMMAND to be "read" with no
>> names:
>> >    |     ${| read; }
>> >
>> > I'd have thought a more likely example would be
>> >
>> >       ${| printf -v REPLY 'whatever format' arg... ;
>>
>> Maybe, and certainly possible, but a more likely use is just a simple
>> assignment to REPLY.
>>
>> >
>> > to get specifically formatted text into a shell word, without needing
>> > a fork, which the alternate
>> >       $( printf 'whatever format' arg.... )
>> > would require.
>>
>> I envision a little more complexity than that; a ${| printf -v REPLY ...;
>> }
>> doesn't really require the command substitution at all.
>>
>> > Use of REPLY in particular as the variable to contain the result seems
>> > like just because it is used that way in read (where it is never really
>> > needed, that's the ultimate of useless frills) and select, and so is a
>> var
>> > name already more or less reserved for the shell's internal use (like
>> OPTIND,
>> > OPTARG, IFS, ...) and was just used for the purpose.
>>
>> Probably. The bash implementation is the union of mksh and ksh93's (with
>> one exception, see below), and that part comes from mksh.
>>
>>
>> > In the example you gave, it would be.   To me, the sole use of the ${|
>> form
>> > seems to be that it doesn't delete the trailing \n if any (Chet didn't
>> actually
>> > say that the other forms do delete trailing newlines,
>>
>> That's part of the general description of command substitution that I
>> didn't include in the text describing this feature. But I can make that
>> point explicitly in this section.
>>
>> 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.
>>
>>
>> > I'd have thought it better to simply make ${| be the same as the variant
>> > using the space (there's no hint in the brief spec as to what difference
>> > it would make using tab or newline, if any, though they were expressly
>> > mentioned as possible)
>>
>> 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.
>>
>> > just with newline supression removed.   It would
>> > be possible to do the same with $(| make that suppress trailing newline
>> > removal as well).    That is, keep ${| using stdout for its result,
>> rather
>> > than yet another meaingless use of REPLY.
>>
>> I decided not to seek deliberate incompatibility with mksh.
>>
>> > And I fail to see any need at all for the ${( form - I see no difference
>> > in that one from $( ) except more, and more difficult, syntax, hence
>> > completely pointless, unless there was something missing I failed to
>> grasp.
>>
>> 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.
>>
>>
>> > Personally, rather than the "nameless function" semantic, I'd prefer the
>> > exact opposite - a word expansion form which runs a named function
>> (just like
>> > any other function, without forking) and substitutes its stdout.
>>
>> 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, but you can certainly call a
>> shell function there with the expected semantics.
>>
>> What I mean is that
>>
>> set -- 1 2
>> x=${ shift; echo "$@"; }
>> echo $x "$@"
>>
>
> so that i understand ,
>
> var=${ awk ... }
>
> ${| awk } no difference
>
> .. and the } as own word .. some rule word something rule .. ?
>
>
> outputs `2 2'. But you absolutely can have "a word expansion form which
>> runs a named function (just like any other function, without forking) and
>> substitutes its stdout" with little effort.
>>
>>
>> > But to go back to the first few words of the previous para - a command
>> > substitution is never going to be a "normal" function call, and I cannot
>> > see any benefit in allowing that form (and only that one - if it were
>> simply
>> > a possible side effect of a more general mechanism, that would be
>> different)
>> > to alter the external positional parameter list.
>>
>> It's to allow local variables and `return'. The existing implementations
>> all agree on that.
>>
>> >
>> > Trying to explain to someone what
>> >
>> >       "$*${ set -- a b c;}$*"
>> >
>> > produces, and why that's a good idea, would be kind of difficult I
>> think.
>>
>
> after ${| set -- 1 2 3 } , 1 2 3 are no more .. right ?
>

;} or space} to end .. ?


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. You expand parameters to the values they have at
>> the
>> time of the expansion. It's how the existing implementations behave, and
>> not particularly difficult to understand.
>>
>>
>> > if the "${ " thing weren't being explained (and presumably implemented)
>> as
>> > a function,
>>
>> I said it superficially resembles function execution, to the extent that
>> local variables and `return' work.
>>
>> > then the "set" example above would just be another example.  But
>> > as it is to be more or less a function, complete with local vars, it
>> should
>> > (whether implemented as a nameless function, or as a call of a named
>> one)
>> > be a real function call, with no variant semantics (and so, a local set
>> of
>> > positional parameters).
>>
>> There's no reason to be deliberately incompatible. 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.
>>
>> > Chet: since field splitting and pathname expansion come after word
>> expansions
>> > you're also going to need to explain what happens with things like
>> >
>> >       "${ IFS= ; echo foo; }${ unset IFS; echo bar;}${ IFS=' '; echo a
>> b c;}"
>>
>> Unless you declare IFS local, it affects the calling execution
>> environment.
>> The value of IFS when it comes time to do word splitting wins. My advice
>> is
>> not to do that. But for what it's worth, all the implementations expand
>> that to
>>
>> foobara b c
>>
>> because word splitting takes place after the other word expansions.
>>
>> >
>> > and
>> >       "${ set -f; echo '*';}${ set +f; echo '???'; }"
>> >
>> > and lots more like it.
>>
>> Well, that won't do anything since it's in double quotes (so it will
>> output `*???'). But if it were not, mksh and bash output either `*???' or
>> any three-character or longer filenames in the current directory. ksh93
>> outputs `*???' for some reason, but I'm not really interested in figuring
>> out why.
>>
>> Chet
>> --
>> ``The lyf so short, the craft so long to lerne.'' - Chaucer
>>                  ``Ars longa, vita brevis'' - Hippocrates
>> Chet Ramey, UTech, CWRU    chet@case.edu    http://tiswww.cwru.edu/~chet/
>>
>>
>>


reply via email to

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