Date: Mon, 31 Aug 2026 11:44:41 +1200
From: Martin D Kealey <[email protected]>
Message-ID:
<CAN_U6MUio0N-Xkb5TMgwTHJX+=FvP9Oe3m_jNcB=u=js-v2...@mail.gmail.com>
| Similarly, newline+�)� gets recorded as �; )�, though - somewhat
| surprisingly - that's actually accepted as input.
|
| (The Shell seems a bit haphazard in where an empty command is acceptable.
There's no empty command there, just white space. The "empty command"
rule (as in, not allowed) only applies when you're in a situation where
some command is required (and for that, it makes no difference how much
white space, including newlines, are present).
In places like after "if" "then" "else" "do" "{" "(" "|" "&&" "||" ...
commands are required.
| Why after �;� or �&� or �PATTERN)�
You don't have to have commands in any of those places, but if you don't
have one, you can't have a command terminator (';' '&' "|" "&&" etc) either.
| but not after �{� or �(� or �|�?
Those are a reserved work, and operators - they all require a command
to follow.
| POSIX is, erm… idiosyncratic, but why enforce such limitations when not
| doing so would simplify the grammar? What have I missed?)
The grammar in this regard is quite simple, it turns out that empty commands
are easy to permit in a recursive-descent parser (just look at what is
coming next before deciding what to do) but tricker in simple grammar
bases parsers (without creating conflicts). It is also mostly consistent
(but the original was recursive descent, and with those, lots of weirdness
is easily possible.)
kre
ps: The NetBSD shell doesn't enforce the "no empty statements" in exactly
one place, we allow:
empty() { }
as a function definition, which does absolutely nothing (such things can
be useful to embed debugging that can be seen with -x enabled). Doing it
the standard way
empty() { :; }
actually runs the ':' command every time, or the alternative
readonly EMPTY=
empty() { $EMPTY; }
expands $EMPTY every time, so both add cost (mostly relevant when
not using -x obviously). There are of course even greater cost
alternatives like
empty() { 99>&-; }
(though not all shells allow references to fd's > 9). That one actually
does a system call every time. The assumption in that one is that fd 99
is never actually opened, so "closing" it does nothing.
[In bash, one can use just '!' as the command:
empty() { !; }
anywhere a command is required, but that is, like our '{ }', non-standard.
It probably isn't documented though, I didn't check, so don't assume it
won't get fixed sometime.]
Not enforcing the rule in other places doesn't really give anyone any benefits.