bug-bash
[Top][All Lists]
Advanced

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

Re: nofork command substitution


From: Chet Ramey
Subject: Re: nofork command substitution
Date: Wed, 24 May 2023 09:27:43 -0400
User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:102.0) Gecko/20100101 Thunderbird/102.10.1

On 5/23/23 6:52 AM, Koichi Murase wrote:

I really appreciate that the feature ${ command; } is finally
implemented.  I have a function that mimics the behavior of the nofork
command substitution in my project.  I changed the function to switch
to use the new nofork command substitutions in new Bash versions [1]
and tested it in the devel branch of Bash.  The initial push of the
nofork command substitution (commit e44e3d50) did not work at all
because of the same error as reported by Oguz [2].  Now with the
latest push (commit 782af562), it seems to work perfectly so far.

Thanks for testing it.


1. Question about the grammar

    If the first character following the open brace is a '(', COMMAND
is executed in a subshell, and COMMAND must be terminated by a ')'.

I guess this is just a minor wording issue, but if I literally read
the above description, the nofork command substitution starting with
`${(' needs to have the form « ${(COMMAND);} ».  However, as far as I
test it, « ${(COMMAND)} » is also allowed.

Both are valid, but don't get too fond of ${(command)} -- I'm going to
remove it in favor of people using ${ (command); } if they want a subshell.
The parser already did that translation internally, so it was just
syntactic sugar anyway.


I guess `${(' is actually not really
different from the other `${<space>', `${<tab>', and `${<newline>',
but is just a version where the COMMAND starts with a subshell (...).

Exactly.

Then, can I understand the grammar in the following way?  First, there
are two types of nofork command substitutions:

   ${ compound_list }
   ${| compound_list }

where `compound_list' is what is defined by EBNF in POSIX XCU 2.10.2.

You could always look at the shell grammar:

comsub:         DOLPAREN compound_list ')'
                        {
                          $$ = $2;
                        }
        |       DOLPAREN newline_list ')'
                        {
                          $$ = (COMMAND *)NULL;
                        }
        ;

funsub:         DOLBRACE compound_list '}'
                        {
                          $$ = $2;
                        }
        |       DOLBRACE newline_list '}'
                        {
                          $$ = (COMMAND *)NULL;
                        }
        ;



If we understand it in this way, it is natural to include <tab> as an
introducer to the nofork command substitutions in addition to <space>
and <newline> because it is the case in the brace grouping.  The
opening paren `(' is also the same.  There seems to be a suggestion to
exclude <tab>, but I think it is strange and inconsistent to exclude
<tab>.  By the way, if we would be more strictly consistent with the
grammar in the brace grouping, the delimiters `<' and `>' should also
introduce nofork command substitutions, such as `${< file.txt;}'
(which would be a synonym of `$(< file.txt)', I guess) or `${<
file.txt sed s/a/b/g;}'.

I don't think either of those is necessary.


2. About the ending brace

There seems to be a suggestion to allow « } » in an arbitrary position
to terminate the nofork command substitution, but I'm actually opposed
to the suggestion even if it is different from the undocumented
behaviors of ksh and mksh.

I'm not going to do that. I'm surprised ksh93 and mksh allow it.

----

3. ${(...)} vs $(...)

There seems to be a doubt in introducing `${( compound_list )}' as a
construct distinct from the normal command substitution `$(
compound_list )', but I do need `${( compound_list )}' because the
normal command substitution doesn't create a process group while the
subshell (...) in the nofork command substitution creates it.

Then use ${ (compound_list); }. It's equivalent and doesn't need special
handling.


4. Use cases of ${| ... }

        [...]

Having a substitution through a variable `${| compound_list }' along
with the one through stdout `${ compound_list }' is very reasonable
from my perspective as a user of Bash as a scripting language.  In
addition, as Chet pointed out, return-via-variable can be done without
calling any syscalls and is much more efficient than constructing a
pipe, writing data, reading data, and tearing down the pipe.

It's not a pipe, right now it's an anonymous file. pipes have size limits
and blocking behavior, and you don't want that for something that's
performed without forking and has to be able to handle arbitrary amounts
of data.

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]