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.