Discussion:
Empty sub-shells and command groups in /bin/sh
(too old to reply)
Robert Elz
2016-05-17 10:07:31 UTC
Permalink
The posix shell standard does not allow empty sub-shells, or command
groups. That is, both
( )
and
{ }
(even if you write the latter as "{ ; }" though it turns out the ';'
there is not actually required, as it, or a \n, usually is before '}')
are both syntax errors.

NetBSD's shell accepts both currently (see PR bin/51145).

I am planning on (or considering) fixing that, and making both
be syntax errors.

I cannot imagine any normal usage being bothered by that, creating a
sub-shell, or a command list, and putting nothing in it is not a very
productive exercise - especially since both bash and dash generate
syntax errors for these (so it is unlikely that any of the zillions of
linux grown scripts will use that syntax either.)

However, most other shells (like NetBSD's) do not object. zsh strangely
objects to the form with '( )' but not the '{ }' version.

The one case where I can see empty command lists being useful is in
function definitions.

That is, I know I like to write

f() {
}

and then sometime later, come back and fill in a body for the fuction.
Perhaps much later - you may have noticed a change I just made to one of
the sh tests which was for exactly this issue - there is a test planned
for which no code has yet been written, so it was just an empty function.
(Well, it contained a comment, but comments, and whitespace, are irrelevant
for this purpose.)

I have implemented a fix for PR bin/51145 but not yet committed it yet.
If desired, I believe (though have not yet actually done) make it so that
function bodies are an exception (an extension of the standard - we already
have that by also allowing a simple command as a function body, POSIX only
permits compound commands.)

That is, if people here think it worthwhile, then

f() {
# optional comments
}

would remain accepted, whereas

if true; then { } else ... fi

would not. Note that to fix any bad usages, all that's needed is something
(more than comments and white space) inside the group, the obvious choice is
the ':' command

( : )

is fine, as is

{ :;}

(the semi-colon is required there, with or without a space after it.)

But other things are also possible

(x=1)

(assign a variable a value, in a sub-shell, which means its value is
immediately lost again) or

{ >&1; }

(redirect standard output onto itself) Etc...

So, before I commit this fix (I have tested that a shell with it included
does build NetSD correctly. but so far not much beyond that) does anyone
have any opinions on the matter ?

kre

ps: various other places, beyond the one from PR bin/48489 (which is
fixed already I believe) where empty "commands" were permitted will also
get corrected by this fix.
Christos Zoulas
2016-05-17 16:05:57 UTC
Permalink
Post by Robert Elz
The posix shell standard does not allow empty sub-shells, or command
groups. That is, both
( )
and
{ }
(even if you write the latter as "{ ; }" though it turns out the ';'
there is not actually required, as it, or a \n, usually is before '}')
are both syntax errors.
[stuff deleted]
Post by Robert Elz
ps: various other places, beyond the one from PR bin/48489 (which is
fixed already I believe) where empty "commands" were permitted will also
get corrected by this fix.
I think we should probably have "strict posix mode" for this (via an
environment variable or command line switch?) ...
Allowing relaxed syntax like this is convenient.

christos
David Holland
2016-05-17 16:10:37 UTC
Permalink
Post by Christos Zoulas
Post by Robert Elz
The posix shell standard does not allow empty sub-shells, or command
groups. That is, both
( )
and
{ }
(even if you write the latter as "{ ; }" though it turns out the ';'
there is not actually required, as it, or a \n, usually is before '}')
are both syntax errors.
[stuff deleted]
Post by Robert Elz
ps: various other places, beyond the one from PR bin/48489 (which is
fixed already I believe) where empty "commands" were permitted will also
get corrected by this fix.
I think we should probably have "strict posix mode" for this (via an
environment variable or command line switch?) ...
Allowing relaxed syntax like this is convenient.
For braces, yes - that is at least semantically sensible. For a
subshell, I'd say not so much.

Also, accepting invalid syntax that other shells reject eventually
bites us.
--
David A. Holland
***@netbsd.org
Robert Elz
2016-05-17 22:44:37 UTC
Permalink
Date: Tue, 17 May 2016 16:05:57 +0000 (UTC)
From: ***@astron.com (Christos Zoulas)
Message-ID: <nhffh5$m9s$***@ger.gmane.org>

| I think we should probably have "strict posix mode" for this (via an
| environment variable or command line switch?) ...

That we have already. (Both variants, and set -o)

| Allowing relaxed syntax like this is convenient.

Three choices (or maybe 4) - all of it (all places where the old shell
permitted empty commands like "sh -c '&&'" ? There seems to have been
no fallout at all from changing that one.

All the grouping commands '( )' '{ }' and 'fn() { }' ?

As David Holland suggested, just the '{ }' (and in that case, automatically)
'fn() { }'

Or just for function definitions? Or perhaps some other combination,
though I suspect those are the most likely ones.

Any are possible, either all the time, or allowing them only in non-posix mode.

Which do you (and everyone else) prefer ?

kre
Robert Elz
2016-05-18 00:03:16 UTC
Permalink
Oh, and while I am here, another possible change, especially if we are
doing things only in posix mode, is in the way the ! word is processed.

In posix, ! is allowed in exactly one place (and there can be only one ! there).

That one place is before a pipeline (note that all simple commands
are also pipelines, just ones containing only one process, and no pipes...)

That is
! false
is OK, as is
! mount | grep | ...

but
! ! false
is not, nor is
mount | ! grep | ...

! also cannot be used ahead of any compound command (no ! ( ... )
or ! while ... etc)

The posix syntax actually makes some sense, the ! ! syntax we simply treat
as a no-op (it does nothing at all - any even number of ! words, any odd
number is the same as 1) and in pipes (ones with more than one command) the
exit status is defined as the exit status of the last command, all the other
processes' exit statuses (statii?) are ignored. So, if we want the opposite
exit status, a single ! in front of the whole pipeline is sufficient.
Putting a ! in front of any of the other commands (would) just cause its
exit status to be inverted before being ignored... (but if you really want
to do it
mount | { ! grep ; } |
is legal (useless, but legal).

I was not planning on changing how the NetBSD shell handles ! but I could
in posix mode, making ! legal only where it should be, and not in the myriad
of other places the shell currently processes it.

Opions?

kre

ps: Also, if we do keep ! ! should it be changed to work as (for example) !!x
does in C, which is the same as "x ? 1 : 0" ? Currently the implementation
(ignoring even numbers of !'s) means we get "x ? x : 0" (ie: x).
Robert Elz
2016-05-22 11:56:32 UTC
Permalink
Date: Tue, 17 May 2016 16:10:37 +0000
From: David Holland <dholland-***@netbsd.org>
Message-ID: <***@netbsd.org>

| On Tue, May 17, 2016 at 04:05:57PM +0000, Christos Zoulas wrote:
| > In article <***@andromeda.noi.kre.to>,
| > Robert Elz <***@munnari.OZ.AU> wrote:
| > >The posix shell standard does not allow empty sub-shells, or command
| > >groups. That is, both
| > > ( )
| > >and
| > > { }

| > I think we should probably have "strict posix mode" for this

| For braces, yes - that is at least semantically sensible. For a
| subshell, I'd say not so much.

OK, absent further comment, the current plan is to simply ban empty
commands (truly empty, in the input form) as posix requires, except
for '{ }' which will only generate an error in posix (standards compliant)
mode (the options for which exist already.)

Any objections?

kre

Loading...