Reading POSIX specification for case conditional construct, I see:

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

As I understand, there will be at least one condition in body of case, and the compound-list corresponded with that condition must be existed.

I wrote a quick test:

$ cat test.sh
case $1 in

case $1 in
  .) ;;
  *) echo 1


$ for shell in /bin/*sh; do
    printf '=%-18s=\n' "$shell"
    "$shell" ./test.sh .
=/bin/ash          =
=/bin/bash         =
=/bin/dash         =
=/bin/heirloom-sh  =
=/bin/ksh          =
=/bin/lksh         =
=/bin/mksh         =
=/bin/pdksh        =
=/bin/posh         =
=/bin/schily-osh   =
=/bin/schily-sh    =
=/bin/sh           =
=/bin/yash         =
=/bin/zsh          =

(/bin/heirloom-sh is the Bourne shell from heirloom tool chest, /bin/schily-sh and /bin/schily-osh are the Schily Bourne shell)

It surprised me! All my known shells accepted the syntax. And also:

case $1 in esac

work in all shells above but ksh (That's ksh93u+ in my system), although it worked in ksh88 as confirmed by schily.

So is it allowed by POSIX or I missed something?

  • When a standard is at variance with every implementation you can think of, it is the specification that is wrong (it happens) or you've misinterpreted it. Sure, that's a semantic argument of "wrong", but practically, adhering to the spec just won't work.
    – msw
    Commented Dec 22, 2015 at 5:53
  • Let me add a note: /opt/schily/bin/osh is preferred over /usr/5bin/sh as it also aims to present a portable version of the OpenSolaris Bourne Shell but includes less bugs that have been introduced from making it portable.
    – schily
    Commented Dec 22, 2015 at 10:22
  • @schily: Yes, I know. You have noticed me sometimes ago. The order in my test is meaningless.
    – cuonglm
    Commented Dec 22, 2015 at 10:24
  • BTW: fot those that did not read about the difference before: /opt/schily/bin/osh and /opt/schily/bin/sh are compiled from the same sources but osh only includes the portability changes and some bugfixes for hard problems while sh is including a lot of additional code that adds features and that make it behave very close to a POSIX shell. See: schilytools.sourceforge.net/bosh.html for a list of new features and features that are still missing for POSIX compliance.
    – schily
    Commented Dec 22, 2015 at 10:29
  • i always do ${sh##*/} so i dont have to wind up talking to anybody about my paths.
    – mikeserv
    Commented Dec 22, 2015 at 10:33

1 Answer 1


Here are the grammar rules, if it helps. I'm not great at reading it, but it sure looks allowed - for every pattern + list case there's also a pattern + break case. That third one would seem to indicate you might even go totally patternless. The link is here.

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

Anyway - it makes sense to me that it should work. The following works:

if $x; then $x; else echo this doesnt happen; fi

...because the commands are not empty when parsed and the shell has something to do. I always associate a pattern with an attached list directly. And in fact, they are pretty well conjoined.

for z in a b c d e f g
do    case $z in [abcd]) ;; $((x+=1))) ;; esac
done; echo "$x"


The spec is pretty clear about about the order of expansions and pattern - list associations. I always just naturally conjoin the two and consider them as more or less a single command. And so because the shell does something, it can check that box off. It probably has something to do with the way a C switch case works.

  • 1
    Ah, the grammar make sense that the empty compound-list is allowed. But how about the empty case list? I don't see it in grammar. Your if example did not seem to be similar with the empty case. The if body had at least $x for the shell to parse. While the case body had nothing.
    – cuonglm
    Commented Dec 22, 2015 at 6:26
  • @cuonglm - what do you mean? its left out for all of them. and the if expands $x while parsing just as case expands the patterns - each in order and stopping at the first match in the same way. a case will never expand any patterns beyond a match because the test is passed and the expansion part of the parse is done at that point.
    – mikeserv
    Commented Dec 22, 2015 at 6:35
  • I mean the parsing occur before expansion. Like when you do if $x; then ; fi you got syntax error, case $x in esac work well.
    – cuonglm
    Commented Dec 22, 2015 at 6:37
  • @cuonglm - that's not how it works w/ case. not really - it needs the delimiters - but each pattern / list pair is parsed and expanded together. once a match is found all of the rest is ignored up to esac - as long as very special shell chars like ( and ) dont interfere with its recognizing esac. so if you had list 3 pages long and you matched the first pattern most of the time, you'd have a fast test anyway.
    – mikeserv
    Commented Dec 22, 2015 at 6:40
  • Right, I know it but I still confuse about the way shell parse. It's interesting that case $x in esac work in all my shell test above, except ksh93.
    – cuonglm
    Commented Dec 22, 2015 at 6:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .