< Day Day Up > |
12.5. Conditional Constructs and Flow ControlConditional commands allow you to perform some task(s) based on whether a condition succeeds or fails. The if command is the simplest form of decision making. The if/else commands allow a two-way decision construct, and the if/elif/else commands allow a multiway decision construct. The Korn shell expects a command to follow an if. The command can be a system command or a built-in command. The exit status of the command is used to evaluate the condition. To evaluate an expression, the built-in test command is used. This command is also linked to the [ and the [[ symbols. The Bourne shell encloses an expression in a set of single brackets: [ and ]. The Korn shell has a more sophisticated method for testing expressions. The expression is enclosed in double brackets: [[ and ]]. In the single brackets, the expansion of wildcards is not allowed; with the double brackets, wildcard expansion is supported and a new set of operators has been added. The result of a command is tested, with zero status indicating success, and nonzero status indicating failure. 12.5.1 Testing Exit Status and the $? VariableThe ? variable contains a number value (between 0 and 255) representing the exit status of the last command that exited. If the exit status is zero, the command exited with success; if nonzero, the command failed in some way. You can test the exit status of commands and use the test command to test the exit status of expressions. The following examples illustrate how the exit status is tested. The single brackets are used in the Bourne shell, and although perfectly acceptable in the Korn shell, Dr. Korn provides you with the new double-bracket notation for testing expressions. Example 12.14.(The Command Line) 1 $ name=Tom 2 $ grep "$name" datafile Tom Savage:408-124-2345 3 $ print $? 0 # Success 4 $ test $name = Tom 5 $ print $? 0 # Success 6 $ test $name != Tom $ print $? 1 # Failure 7 $ [ $name = Tom ] # Brackets instead of the test command 8 $ print $? 0 9 $ [[ $name = [Tt]?m ]] # New ksh test command 10 $ print $? 0 EXPLANATION
12.5.2 The Old test CommandThe test command is used to evaluate conditional expressions, returning true or false. It returns zero exit status for true, and nonzero exit status for false. Either the test command or the brackets can be used. The Korn shell introduced a new way of testing expressions with double brackets. For backward compatibility with the Bourne shell, the older form of test can be used with either the test command or the single brackets. However, the preferred method for Korn shell programmers is the new test with double brackets. A complete list of test operators (both old and new style) appear in Table 12.6.
12.5.3 The New test CommandWith the [[ . . . ]] compound test command, additional operators are available. Wildcards can be used in string-matching tests, and many of the errors from the old test have been eliminated. New string test operators are listed in Table 12.7. Example 12.15.(The Script) read answer 1 if [[ $answer = [Yy]* ]] # Test for Yes or yes or Y or y, etc. then... Example: (The Script) guess=Noone 2 if [[ $guess != [Nn]o@(one|body) ]] # Test for Noone, noone, or Nobody, nobody... then. . . Example: (The Command Line) 3 [[ apples < oranges ]] print $? 0 4 [[ apples > oranges ]] print $? 1 5 $ name="Joe Shmoe" $ [ $name = "Abe Lincoln" ] # old style ksh: Shmoe: unknown test operator 6 $ [[ $name = "Abe Lincoln" ]] # new style $ echo $? 1
EXPLANATION
12.5.4 File Testing with Binary OperatorsThe binary operators for testing files require two operands (i.e., a file on either side of the operator). See Table 12.8 for a list of binary file-testing operators.
12.5.5 Expression Testing with Logical OperatorsThe Korn shell, like C, provides logical testing of the truth or falsity of expressions. They are listed in Table 12.9.
12.5.6 File Testing with FlagsThe Korn shell provides a number of built-in test commands for checking the attributes of files, such as existence, type, permissions, and so forth. The file-testing options (also called flags) are listed in Table 12.10. Example 12.16.
(The Script)
1 file=/etc/passwd
2 if [[ -f $file && (–r $file || –w $file) ]]
then
3 print $file is a plain file and is either readable or writable
fi
EXPLANATION
12.5.7 The if CommandThe simplest form of conditional is the if command. The command following the if keyword is executed and its exit status is returned. If the exit status is 0, the command succeeded and the statement(s) after the then keyword are executed. In the C shell and C language, the expression following the if command is a Boolean-type expression. But in the Bourne and Korn shells, the statement following the if is a command or group of commands. The exit status of the last command of the if line is used to determine whether to continue and execute commands under the then statement. If the exit status of the last command on the if line is 0, the commands under the then statement are executed. The fi terminates the command list to be executed after the then. If the exit status is nonzero, meaning that the command failed in some way, the statement(s) after the then statement are ignored and control goes to the line directly after the fi statement. Conditional commands can be nested. Every if must have a corresponding fi. The fi is paired with the closest if. Using indentation to format your if blocks helps when debugging your programs. FORMAT if command then # Testing command exit status command command fi ------------------------------------ if test expression then # Using the test command to test expressions command fi or if [ expression ] then # Using the old-style test command-- command # brackets replace the word test fi ---------------------------------- if [[ expression ]] then # New-style brackets for testing expressions command fi ---------------------------------------------- if command then ... if command then ... if command # Nested conditionals then ... fi fi fi Example 12.17.1 if ypmatch $name passwd > /dev/null 2>&1 2 then echo Found $name! 3 fi EXPLANATION
12.5.8 Using the Old-Style Bourne testIf you have been programming in the Bourne shell, the Korn shell is backward-compatible, allowing your Bourne shell scripts to be executed properly by the Korn shell. Many Bourne shell programmers, when converting to Korn shell, still use the old-style test command when evaluating expressions. If you are reading or maintaining scripts, you may find the old syntax alive and well. Therefore, a brief discussion of the old syntax may help you, even if you are writing your own scripts with the new Korn shell test command. Example 12.18.#!/bin/ksh # Scriptname: are_you_ok 1 print "Are you ok (y/n) ?" read answer 2 if [ "$answer" = Y -o "$answer" = y ] # Old-style test then print "Glad to hear it." 3 fi EXPLANATION
12.5.9 Using the New-Style Korn testThe new-style Korn shell testing allows expressions to contain shell metacharacters and Korn shell operators such as && and ||. Example 12.19.#!/bin/ksh # Scriptname: are_you_ok2 1 print "Are you ok (y/n) ?" read answer 2 if [[ "$answer" = [Yy]* ]] # New-style test then print "Glad to hear it." 3 fi EXPLANATION
12.5.10 Using the Old-Style Bourne test with NumbersTo test numeric expressions, the old-style Bourne shell test command and its operators are still acceptable in the Korn shell, but the new-style let command is preferred. Example 12.20.
1 if [ $# -lt 1 ]
then
print "$0: Insufficient arguments " 1>&2
exit 1
2 fi
EXPLANATION
12.5.11 The let Command and Testing NumbersAlthough it is still acceptable to use single square brackets and old-style Bourne shell numeric operators for testing numeric expressions, the preferred Korn shell method is to use the double parentheses and the new C language–style numeric operators when testing numeric expressions. Note that the double brackets are only used for testing string expressions and for file tests (see Table 12.10). Example 12.21.
1 if (( $# < 1 ))
then
print "$0: Insufficient arguments " 1>&2
exit 1
2 fi
EXPLANATION
12.5.12 The if/else CommandThe if/else command allows a two-way decision-making process. If the command after the if fails, the commands after the else are executed. FORMAT if command then command(s) else command(s) fi Example 12.22.1 if ypmatch "$name" passwd > /dev/null 2>&1 2 then print Found $name! 3 else 4 print "Can't find $name." exit 1 5 fi EXPLANATION
12.5.13 The if/elif/else CommandThe if/elif/else command allows a multiway decision-making process. If the command following the if fails, the command following the elif is tested. If that command succeeds, the commands under its then statement are executed. If the command after the elif fails, the next elif command is checked. If none of the commands succeeds, the else commands are executed. The else block is called the default. FORMAT if command then command(s) elif command then commands(s) elif command then command(s) else command(s) fi --------------------------------------------------------------------- if [[ string expression ]] or if (( numeric expression )) then command(s) elif [[ string expression ]] or elif (( numeric expression )) then commands(s) elif [[ string expression ]] or elif(( numeric expression )) then command(s) else command(s) fi Example 12.23.(The Script) #!/bin/ksh # Scriptname: tellme 1 read age?"How old are you? " 2 if (( age < 0 || age > 120 )) then print "Welcome to our planet! " exit 1 fi 3 if (( age >= 0 && age < 13 )) then print "A child is a garden of verses" elif (( age > 12 && age < 20 )) then print "Rebel without a cause" elif (( age >= 20 && age < 30 )) then print "You got the world by the tail!!" elif (( age >= 30 && age < 40 )) then print "Thirty something..." 4 else print "Sorry I asked" 5 fi (The Output) $ tellme 1 How old are you? 200 2 Welcome to our planet! $ tellme 1 How old are you? 13 3 Rebel without a cause $ tellme 1 How old are you? 55 4 Sorry I asked EXPLANATION
12.5.14 The exit CommandThe exit command is used to terminate the script and get back to the command line. You may want the script to exit if some condition does not test true. The argument to the exit command is an integer, ranging from 0 to 255. When the program exits, the exit number is stored in the shell's ? variable. Example 12.24.(The Script) #!/bin/ksh # Scriptname: filecheck # Purpose: Check to see if a file exists, what type it is, and its permissions. 1 file=$1 # Variable is set to first command-line argument 2 if [[ ! -a $file ]] then print "$file does not exist" exit 1 fi 3 if [[ -d $file ]] then print "$file is a directory" 4 elif [[ -f $file ]] then 5 if [[ -r $file && -w $file && -x $file ]] then print "You have read, write, and execute permission on file $file" else 6 print "You don't have the correct permissions" exit 2 fi else 7 print "$file is neither a file nor a directory. " exit 3 8 fi (The Command Line) 9 $ filecheck testing testing does not exist 10 $ echo $? 1 EXPLANATION
12.5.15 The null CommandThe null command is a colon. It is a built-in, do-nothing command that returns an exit status of 0. It is used as a placeholder after an if command when you have nothing to say, but need a command or the program will produce an error message because it requires something after the then statement. Often the null command is used as an argument to the loop command to make the loop a forever loop or for testing variable expression modifiers such as {EDITOR:–/bin/vi}. Example 12.25.(The Script) 1 name=Tom 2 if grep "$name" databasefile > /dev/null 2>&1 then 3 : 4 else print "$1 not found in databasefile" exit 1 fi EXPLANATION
Example 12.26.
(The Script)
1 : ${EDITOR:=/bin/vi}
2 echo $EDITOR
EXPLANATION
12.5.16 The case CommandThe case command is a multiway branching command used as an alternative to the if/elif commands. The value of the case variable is matched against value1, value2, and so forth until a match is found. When a value matches the case variable, the commands following the value are executed until the double semicolons are reached. Then, instruction starts after the word esac (case spelled backwards). If a case variable is not matched, the program executes commands after the *), the default value, until the double semicolons or esac is reached. The *) value serves the same purpose as the else statement in if/else conditionals. The case values can use shell wildcards and the vertical bar (pipe symbol) for ORing two values. FORMAT case variable in value1) command(s);; value2) command(s);; *) command(s);; esac Example 12.27.(The Script) #!/bin/ksh # Scriptname: xtermcolor # Sets the xterm foreground color (the color of the prompt and # input typed for interactive windows. 1 read color?"Choose a foreground color for your terminal?" 2 case "$color" in 3 *[Bb]l??) 4 xterm -fg blue -fn terminal & 5 ;; 6 *[Gg]reen) xterm -fg darkgreen -fn terminal & ;; 7 red | orange) # The vertical bar means "OR" xterm -fg "$color" -fn terminal & ;; 8 *) xterm -fn terminal & # default ;; 9 esac 10 print "Out of case..." EXPLANATION
The case Command and the here documentOften, the here document is used to create a menu. After the user has selected a choice from the menu, the case command is used to match against one of the choices. The Korn shell also provides a select loop for creating menus. Example 12.28.(The .profile File) print "Select a terminal type " 1 cat << EOF 1) vt120 2) wyse50 3) ansi 4) sun 2 EOF 3 read TERM 4 case "$TERM" in 1) export TERM=vt120 ;; 2) export TERM=wyse50 ;; 3) export TERM=ansi ;; *) export TERM=sun ;; 5 esac print "TERM is $TERM" EXPLANATION
|
< Day Day Up > |