#!/bin/sh

#   Yes, you can execute this whole script for demonstration.

#   Of course you also remember comments, the here document, and the :
#   command, right? :-)  Okay, so I effectively (but not literally)
#   comment out the part between the pairs of __EOT__ without having to
#   individually comment out most or all the lines in that section.

>>/dev/null 2>&1 : << \__EOT__

    #   case syntax:

case word in [ pattern [ | pattern ] ... ) list ;; ] ... esac

    #   here the square bracket ([]) characters aren't meant literally,
    #   but rather indicate the enclosed portion is optional
    #   the ... indicates the preceding (optional) portions can be
    #   repeated zero or more times

    #   so, let's look again, in some more detail:

case word in [ pattern [ | pattern ] ... ) list ;; ] ... esac

    #word is a word - sequence of one or more non-blank characters (can
    #----               contain blanks if quoted, can be result of
    #                   various types of substitution, can be null if
    #                   quoted)

    #          pattern a pattern specification to potentially match word
    #          -------  against, as described under File name generation
    #                   on sh(1)

    #                    | pattern - multiple patterns can be specified
    #                    ---------  by separating them with |

    #                                    )
    #                                    - literal right parenthesis
    #                                       character

    #                                      list list to be executed if
    #                                      ---- preceeding corresponding
    #                                           pattern(s) match (only
    #                                           the first list matching
    #                                           pattern is executed)

    #                                           ;; ] ... esac
    #                                           -------------
    #                                           ;; effectively marks the
    #                                           end of list
    #                                           corresponding to the
    #                                           preceeding pattern(s),
    #                                           an arbitrary number of
    #                                           pattern through list ;;
    #                                           portions can be
    #                                           specified, at most one
    #                                           list is executed (that
    #                                           corresponding to the
    #                                           first pattern in the
    #                                           case that's matched),
    #                                           the esac is keyword
    #                                           needed to end the case
    #                                           command

# where we must/can/can't have "blanks" (one or more space(s) and/or
# tab(s)) and/or "whitespace" (one or more "blanks" and/or newline(s))
# (see also examples):

# we need blanks between case and word
# we need whitespace between word and pattern
# we can have blanks around | separating patterns
# we can have blanks between pattern and )
# we can have whitespace between ) and list
# we can have whitespace between list and ;;
# we must have whitespace between list and ;; if list ends with
#   semicolon (;)
# we can have whitespace between ;; and pattern or esac

__EOT__

# if $1 is not set, we set it to 15
# "${1-15}" gives us "$1" if $1 is set, "15" otherwise
# we then use set to set that as our first (and now only) positional parameter
set -- "${1-15}"
# as side effect, we unset an other positional parameters
# you can execute this script with arguments, to change $1 from the default
# value of 15

# you can also try with it unset or try setting it to something that
# doesn't match the first set of patterns that's used for most of the
# examples

# We'll track if we got error(s), rather than immediately bailing out
error=no

# Typical fairly readable use in scripts:
case "$1" in
	[0-9]|[1-9][0-9])
		echo OK ...
	;;
	*)
		1>&2 echo "$0: expecting \$1 between 0 and 99, got $1"
		error=yes
	;;
esac

# Typical fairly readable use in scripts with a bit more liberal
# whitespace:
case "$1" in
	[0-9] | [1-9][0-9] )
		echo OK ...
	;;
	* )
		1>&2 echo "$0: expecting \$1 between 0 and 99, got $1"
		error=yes
	;;
esac


# Very difficult to read version with same functionality with an
# unquoted newline everywhere we can get away with using it for
# whitespace, no unneeded blanks, and no tabs:
case "$1"
in
[0-9]|[1-9][0-9])
echo OK ...
;;
*)
1>&2 echo "$0: expecting \$1 between 0 and 99, got $1"
error=yes
;;
esac


# without newlines:
case "$1" in [0-9]|[1-9][0-9]) echo OK ...;; *) 1>&2 echo "$0: expecting \$1 between 0 and 99, got $1"; error=yes;; esac
# note that in the example above, our only use of ; (other than ;;) is
# where we require it within a list

# even less readable version with minimum whitespace and no newlines
case "$1" in [0-9]|[1-9][0-9])echo OK ...;;*)1>&2 echo "$0: expecting \$1 between 0 and 99, got $1";error=yes;;esac

# note also from the syntax, that most sections are optional, so we can
# also have quite trivial valid case commands:
case '' in esac
case ''
in
esac

# did we get any errors that we tracked?
if [ X"$error" = Xyes ]; then
	1>&2 echo "$0: we didn't pass some of our tests, aborting"
	exit 1
else
	echo "$0: we completed our tests successfully."
	exit 0
fi
