Mark Galeck Mark Galeck - 4 months ago 9
Bash Question

can the first compound list in POSIX shell case construct have alternatives among patterns?

The POSIX shell standard

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html

says

The format for the case construct is as follows:

case word in
[(]pattern1) compound-list;;
[[(]pattern[ | pattern] ... ) compound-list;;] ...
[[(]pattern[ | pattern] ... ) compound-list]
esac


which seems to indicate the first compound list pattern is special - there can be only one, no alternatives denoted by
|
as for the other ones (and reading the POSIX standards elsewhere,
pattern
itself does not support alternatives).

I tried, using latest
dash
, and seems to work:

$case foobar in
( foo* | *bar ) echo OK
esac
$OK


There is no mention of "behavior is unspecified". So if the shell did not support that, it should emit an error message.

It cannot be a typo in the standard - too many characters involved.

So clearly I am not understanding something. Does POSIX shell support alternatives among patterns for the first compound list of a case construct, and how is it documented?

Answer

The canonical grammar is given in the standard:

case_clause      : Case WORD linebreak in linebreak case_list    Esac
                 | Case WORD linebreak in linebreak case_list_ns Esac
                 | Case WORD linebreak in linebreak              Esac
                 ;
case_list_ns     : case_list case_item_ns
                 |           case_item_ns
                 ;
case_list        : case_list case_item
                 |           case_item
                 ;
case_item_ns     :     pattern ')'               linebreak
                 |     pattern ')' compound_list linebreak
                 | '(' pattern ')'               linebreak
                 | '(' pattern ')' compound_list linebreak
                 ;
case_item        :     pattern ')' linebreak     DSEMI linebreak
                 |     pattern ')' compound_list DSEMI linebreak
                 | '(' pattern ')' linebreak     DSEMI linebreak
                 | '(' pattern ')' compound_list DSEMI linebreak
                 ;
pattern          :             WORD         /* Apply rule 4 */
                 | pattern '|' WORD         /* Do not apply rule 4 */

Note that pattern, which allows |s, is used in every position.