Date:        Mon, 20 Apr 2020 07:12:03 +0000
    From:        "Schwarz, Konrad" <konrad.schw...@siemens.com>
    Message-ID:  <38be7e5d52c74c9dac140f7de5105...@siemens.com>

  | Not sure if I understand your problem,

I suspect probably not.

  | but I've always understood the
  | case xxx in
  | (pattern) ...;;
  |                 esac
  |
  | (fully parenthesized pattern) syntax to have been invented precisely
  | to allow case statements in $() subshell notation,

First, $() is command substitution, not a subshell (not really important)
and if that was someone's intent, they did a particularly bad job of
implementing it, as what the standard says is (XCU 2.6.3)

        With the $(command) form, all characters following the open
        parenthesis to the matching closing parenthesis constitute the
        command. Any valid shell script can be used for command, except a
        script consisting solely of redirections which produces unspecified
        results.

Note the "any valid shell script" (with that one exception) - a valid shell
script certainly includes a case statement where the optional '(' is
omitted.

My guess has always been that the '(' was invented as a sop to parenthese
balancing editors - to make it possible for those things to assist with
balancing parentheses.   But that's mere speculation, I wasn't around at
the time.  A workaround for broken shells is another possibility.

But the case statement in my e-mail was just an easily understood
(familiar) example I used to illustrate the real point, which relates
to whether or not aliases are to be processed in double-quoted command
substitutions (whether only for the point of finding the terminating ')'
or including actual processing).

A different example...

        alias nest='('
        nest echo foo )

works everywhere (as it should in any posix shell).

        echo $( nest echo foo ) )

works in ash based shells, yash, bosh, mksh, and zsh, but not ksh93
or bash (or ancient pdksh).

That one should work everywhere, the command substitution contains
a valid shell script (which not only is not entirely redirections,
it has no redirections at all).

        echo "$(nest echo foo ) )"

This one works everywhere (including ksh93 and bash) except old pdksh.
But according to the standard, shouldn't, as the standard prohibits
processing the "nest" alias when looking for the end of the command
substitution.

Given that, the command substitution command is (defined to be)

        nest echo foo

which should fail, either because there is no nest command
(if no alias processing is done at all) or because of the
unmatched parentheses if the next alias is later processed
(this last is what pdksh appears to do.)

In this scenario, the trailing " )" is just more data for the
echo command to write.

That is "my problem" - the standard is requiring processing in
a way that no-one relevant does it (any more).  It is time for
this part to be updated (if it hasn't already been.)

I'm not sure I really buy into Harald's "once a syntax error
is found, the shell can do whateber it wants" and I suspect
that given a bit of time to think about it, I could come up with
an example which has no syntax errors but where the intrepretation
differs depending upon whether aliases are processed there or
not.

At the very least, we need an explanation why aliases aren't to be
processed when looking for the closing ')' in a double quoted command
substitution, but are in an unquoted one.   I suspect that the answer
is "because that's how ksh88 implemented it", which in this case is a
poor one - other bugs (and this really cannot be anything except that)
in ksh88 were fixed or worked around in the standard, this one should
have been as well.

Here's another test case to play with:

        alias short='echo foo )'
        ( short

works everywhere.

        echo $( short

works in all ash based shells, bosh, yash, mksh.

bash and zsh are very obviously buggy:

bash$ alias short
alias short='echo foo )'
bash$ ( short
foo
bash$ echo $( short
)
-bash: shor: command not found

)

(bash gave a PS2 prompt, and I typed an extra ')'.   No idea
what it did with my 't'...

zsh $ alias short
short='echo foo )'
zsh $ echo $( short
)
zsh: parse error near `)'
zsh $ echo $( short
zsh: command not found: shortecho

Two tests there, the first (like with bash) I typed a ')' at the
PS2 prompt, or where I assume one was expected (zsh didn't write it)
after which it complained about the excess ')' (which is close to
correct).   If instead I typed a newline where the PS2 prpmpt might
have been, I got the 2nd response.   That's obviously simply a bug.
[I tried the newline response for bash as well, but it simply issued
a new PS2 and waited for more.]

Lastly, with this one

        echo "$( short"

there are no shells that do anything that I would have expected (not
even mine).   All wait for more input, some write PS2 (zsh does this time)
There doesn't seem to be any obvious input that will satisfy any of them
reliably however (SIGINT works).   I was able to (once) get bash to
repeat its "shor: command not found" error in this scenario, after typing
a bunch of gibberish ) and " and )" type responses to the PS2 prompts.
There's clearly some sequence that will get it out of its input state,
but I couldn't determine what.

With the other shells, I couldn't find anything at all (though EOF always
also worked - producing an error, and causing pdksh and mksh to exit as
well...).

But if I make the command instead be

        echo "$( short ;"

then most shells go back to working.   The ash based shells, bosh, yash
all correctly output "foo ;" (with echo's trailing newline of course).
zsh repeats its "zsh: command not found: shortecho" bug, and bash & ksh93
still want more input.  Since mksh and pdksh had exited in the previous test
I didn't test them for this one (yet).

One even odder strange example...

ksh93 $ echo "$( short )"
foo 

I don't want to contemplate what actually happened there, but whatever
it was, was nonsense.  The shells that generally work correctly output
"foo )" for that one, bash and zsh do their "command not found" trick
with the wrong command name.

kre

ps: Naturally, one easy fix for this issue would be to simply deprecate
aliases completely.   That would be one less nightmare to deal with.


Reply via email to