bash case

The second branching structure in the bash shell script is the "case" structure.

Where the "if" structure tests the return status of a specified command, "case" compares the contents of a specified variable against a series of string templates. The templates may use the filename wildcard meta-characters to specify a range or series of possible values.

The general structure of a case structure is :

case "$var" in
  str_template )
    action_cmd[s]
  ;;

  str_template ) action_cmd ;;

  ...

esac

where :

'case' is the keyword that initializes the case structure.

"$var" is the variable to be examined. A string constant can be specified here, but would defeat the point of the case. It is a good practice to quote the variable being examined. In some shells, if the variable is unassigned or contains null, a shell script error could occur.

'in' completes the initializing line of the case.

'str_template )' specifies the 1st string template to compare the variable with. The right parenthesis is required to separate the template from the action to be taken if the variable contents matches template.

'actions_cmd[s]' must be at least one valid command and may be a large block of commands containing ifs, other case structures, and/or the various loop commands. It is possible to use the colon ":" as a valid null command if you are not ready to code specific actions yet.

The number of 'str_template ) action_cmd[s] ;;' sets are unlimited.

Each set is mutually exclusive of all others.

'esac' is the keyword that terminates the case structure.

When a case is encountered, the bash interpreter compares the contents of the specified variable with the 1st template. If no match found, the interpreter compares the variable with the 2nd template. This continues until a match is found or the "esac" is encountered.

It is possible for there to be no successful matches in a case. Script interpretation continues on the first executable line after the "esac".

If a match is found to a template, then all of the commands between the right parenthesis and the double semi-colon will be invoked. Upon encountering the ;;, execution of the shell script continues with the 1st command following the "esac".

Specifying templates :

Remember, the case performs an exact match between the template and variable contents. In order to provide a more flexible template, "case" uses the filename wild card and other shell meta-characters to expand a template.

Examples of templates :

yes ) # matches the 3 character string "yes" all in lower case and only the 3 character string. Match is exact.

"hey there" ) # matches the string "hey there". Because there a space in the string, you must enclose the space in quotes.

hey" "there ) # works the same, as long as the non-space characters are immediately concatenated against the quoted space.

[Yy][Ee][sS] ) # matches the 3 character string "yes", "yes" may be in any combination of upper and lower case. Make sure you do not quote the brackets if using them for a list or range.

yes|YES ) # matches the 3 character string "yes" if it is either all lower or all upper case. Quote | if looking for a literal of it.

[12][0-9] ) # matches a 2 digit number, 1st digit can be either a 1 or 2, the second digit can be any value between 0 and 9. Note that there are no spaces between the left and right bracket. Spaces inside the brackets will be interpreted as spaces to match in the variable.

[0-9][02468] ) matches a 2 digit number that is even.

[a-z][a-z][a-z][a-z] ) # matches a four letter string of any alpha characters. Depending on environmental setting and the actual character sets used (ASCII or Unicode), case sensitivity may be ignored when bracket and a range are combined.

[[:lower:]] # matches a single lower case alpha character. Note the double brackets [[ ]]. Make sure there are no spaces in the brackets. There are several character sets that can be used as long as the double brackets are used. The following should also be available :

  [:alnum:] # numbers and letters.
  [:alpha:] # upper and lower case letters
  [:cntrl:] # control characters
  [:digit:] # any digit in range of 0-9
  [:graph:] # a printable character other than spaces.
  [:lower:] # lower case letters, Using [[:lower:]] should be
              independent of local and character encoding.
  [:print:] # all printable characters (tab is a space but control and
              not printable)
  [:punct:] # punctuation
  [:space:] # space or tabs
  [:upper:] # upper case alpha
  [:xdigit:] # 0-9ABCDEFabcdef
y?? ) # matches a 3 character string beginning with a lower case "y" and the other two may be any value. y* ) # matches a lower case "y" followed by any number of any additional characters, including none.

[yn]* ) # matches either a "y" or "n" followed by any number of other characters.

*) # matches any value. Use this if you want an else action in the case. This case will always cause the action block to be executed, so make sure it is the last case listed.

When coding the order of the case match, if matches overlap, work from specific to general.

Remember, the first match is always acted on and execution then continues after the "esac" close statement.

If cases do not overlap, place the case that will be matched more often 1st.