This month's column continues our exploration of the bash shell's scripting facilities by investigating the case statement. The case statement is particularly useful for handling the arguments of a script. It is both powerful and sophisticated, making it easy to express complex conditions that would tax your patience if you coded them using an if statement.
This month’s column continues our exploration of the bash shell’s scripting facilities by investigating the case statement. The case statement is particularly useful for handling the arguments of a script. It is both powerful and sophisticated, making it easy to express complex conditions that would tax your patience if you coded them using an if statement.
The case Statement
Both if and case are conditional statements; that is, you can use them to take alternative actions based on tests you specify. The power of the case statement lies in the kinds of tests it lets you specify. While the if statement relies on a true/false value, the case statement lets you specify a text string and a series of regular expressions, which it attempts to match against the text string. When a match is found, a series of commands is executed. Here’s the general form of the case statement:
case string in
You can see that the statement begins and ends with the keywords case and esac (the word case spelled backwards). Within the statement, string specifies the value to be matched, followed by one or more patterns to be matched against the string. An indefinite number of pattern lines may be included in a case statement. Note that each pattern line contains a series of commands. Each command within a series is separated from the next by a semi-colon (;), and the entire series is followed by a pair of semicolons.
Here’s a simple example of a case statement:
case $1 in
1) echo “The argument value is 1.” ;;
2) echo “The argument value is 2.” ;;
*) echo “The argument value is something other than 1 or 2.” ;;
If you use a text editor to create a file named case1 containing this script, you can study the operation of the case statement by issuing a command such as:
If you issue this command, the script will likely respond with the message:
The August Newbies column explained how shell arguments work. If you didn’t read that column, you’ll soon be able to access it on the Linux Magazine Web site. The Reader’s Digest version of that column is that shell arguments are sent to scripts as the variables $1, $2, … , $9. So, the value typed on the command line after the word case1 is bound to the shell variable $1. Try some argument values other than 2 and see what results you are able to obtain.
How the case Statement Works
As explained, the case command works by matching a string against a series of patterns. In the simple example given above, the shell variable $1 provides the string value. The patterns appear one to a line, each followed by a right parenthesis.
The first two patterns are literal patterns that match the given character. The first pattern matches the string 1, and the second matches the string 2. The third pattern consists of the metacharacter *, which matches any string.
When the shell executes a case statement, it tries the patterns in the order given. In the example, the shell tries to match the value of $1 against 1. If the match succeeds, the shell prints the message “The argument value is 1″ and exits the case statement. Otherwise, the shell tries to match the value of $1 against 2. If the match succeeds, the shell prints the message “The argument value is 2″ and exits the case statement. If neither of the two preceding patterns matches the value of $1, the shell will try to match the value against *. Because the metacharacter * matches any string, this match will always succeed. So, if neither of the first two patterns matches, the shell will print the message “The argument value is something other than 1 or 2.”
Expanding Your Pattern Vocabulary
The power of the case statement has its root in the language used to express its patterns. The Linux shell and applications support several pattern languages, all of which are more or less the same. Table One summarizes the pattern language supported by the case statement.
Table One: Metacharacters Used in Forming case Statement Patterns
|\c||Matches the literal character c|
|? ||Matches any single character|
|“…” or ||Matches the literal string enclosed within the quotes|
|* ||Matches any series of characters, including the empty series|
|[abc] ||Matches any of the characters a,b,c|
|a|b||Matches the pattern a or b|
|[a-m||Matches any character in the range|
|0-5] ||a-m or 0-9|
In the slightly different pattern language used to specify file names, the characters . and / have special status and must be explicitly matched by a literal pattern character. However, the pattern language used by the case statement does not play favorites; for example, its metacharacter * will readily match either . or /.
You can combine literal characters with the elements given in Table One to form even more sophisticated patterns. For example, you can use the pattern disc to match the strings disc0 and disc1.
Matching Multiple Words
The case statement is designed to match a single word, so matching a phrase such as Linux Magazine requires you to enclose the pattern within quotes. Here’s a script that uses a case statement to check if the script’s argument is Linux Magazine:
case $1 in
*) echo “No match” ;;
If you place this script in a file that is named case2 and invoke it as in the following command, you’ll see the message Match:
sh case2 “Linux Magazine”
However, if you invoke the script like this, you’ll see the message No Match:
Without the double quotes, the string Linux Magazine is treated as two arguments; the word Linux is bound to the shell variable $1, and the word Magazine is bound to the shell variable $2.
It’s sometimes unreasonable to expect that the user of a script will quote the argument string. In such cases, you can work around the problem by specifying the case statement’s string a little differently. Consider the following script:
case “$1 $2″ in
*) echo “No match” ;;
By specifying the string as “$1 $2″, you perform the quoting on behalf of the script user. If you place this script in a file that is named case3 and invoke it as the following command, you will see the message Match notwithstanding the absence of quotes in the invocation:
A More Sophisticated Example
The case statement is used extensively in the Linux system administration scripts. One reason for this is the ability of the case statement to cope with the variety of ways that a human may provide an argument or respond to a prompt. For example, when a user is asked to respond in the affirmative, a human may respond yes,Yes, or even simply y.
Suppose you want to create a script that prompts the user for a yes or no response. Such prompts are almost always used by systems to confirm the user’s desire to execute an irreversible operation; for example, the rm command provides such a prompt when its -i switch is specified. The following shows you how you can use the case command to provide a yes/no prompt:
echo -n “Do you want to continue (y/n): ”
case $reply in
y*|Y*) echo Yes ;;
*) echo No ;;
The script uses an echo command to display a message; the command’s -n switch instructs the command to omit the newline character otherwise displayed as the final character of the output. By omitting the newline character, the user’s response can be provided on the same line as the message.
The read command reads a line of text typed by the user and places the line in the specified environment variable, $reply. The case command tests the reply entered by the user. If the reply begins with the letter y or Y, the string “Yes” is echoed; otherwise, the string “No” is executed. For example, here’s a typical interaction with the script, stored in the file case4:
[bmccarty@athlon linuxmag]$ sh case4
Do you want to continue (y/n): you betcha
To apply this technique in your own scripts, simply replace the prompt string that is displayed by the echo command and the commands associated with the pattern lines.
Notice that if the user responds with something other than yes or no, the script is likely to interpret the response as no. You may not like this behavior, preferring that the script recognize invalid responses and reissuing the prompt rather than assuming a no response. You can use a shell loop to make just such an improvement (which we’ll look at next time).
On the Case…
That closes the case on our tour of the mighty case statement. Next month’s column will address the loop statements provided by the shell. The ability to conditionally repeat shell statements, which they provide, is an enormously powerful and useful facility.
Until then, may all your cases be happy ones!
Bill McCarty is an associate professor at Azusa Pacific University. He can be reached at firstname.lastname@example.org.