Conditional statements execute if and only if a certain condition or conditions are true. They generally come in three forms: if statements, case statements, and logical AND/OR statements. These are very fundamental and useful constructs in programming; flow control depends on them (executing certain blocks of code depending on the outcome of a condition), as does the ability of a program to behave correctly upon receiving certain expected arguments (which would be handled by case statements). if Statementsif statements test numerical expressions given in brackets (which, as you saw earlier, are a shorthand for the test command). If the test condition is true, the statements inside the if block are executed. If the condition is false, one of two things can happen:
For example, the program in Listing 10.15 uses an if statement to test the number of command-line arguments given to the program. If the command-line arguments are one or more, the program performs the operations inside the then block. If no command-line arguments were supplied, the program exits without doing anything. Listing 10.15. Using an if Statement
And here are two sample runs: Run 1: # ./ifprog file1 file2 file3 You supplied 3 command line arguments. Program exiting... Run 2: # ./ifprog Program exiting... The if statement in line 3 checks to see whether the number of command-line arguments supplied is one or greater (using the magic variable $#, which stores the number of command-line arguments). If it is, the statements between then and fi are executed. ("fi" is if spelled backward. It marks the end of the if block.) If it isn't, the statements inside the if block are skipped and the program jumps to the first statement past fi, which in this case simply informs the user that the program is exiting. Using an else StatementYou could make this program more user-friendly by including an else statement that tells the user how to properly use the program rather than simply having it exit without doing anything, as it currently does. Listing 10.16 shows the revised example. Note that the operand in line 3 is a number one, not a lowercase L. Listing 10.16. A More User-Friendly Way to Use if Statements
Now, if the number of command-line arguments is less than one, the program will perform the else statements and give the user a usage message (remember that $0 contains the name of the command that was invoked). Notice also line 9, which tells the program to exit immediately and sets the exit status to 1 (which indicates the program terminated with errors). Statements 1014 will never get executed if the program runs the else statements. The then part of the if statement is required, but the else part is optional. As you have seen, the then part of the if statement performs an action if the expression tested by if evaluates to true. Sometimes, however, you might want to perform an action only if the expression evaluates to false and to do nothing if the expression evaluates to true. You can do this by using a colon as a placeholder. Here's an example: if [ $myVar -gt 5 ] then : # Do nothing and continue after end of if block else # Statements to execute if condition is false go here. fi Using an elif StatementSometimes you might want to test for two or more different conditions and perform a different action, depending on the results. The elif statement (an abbreviation for "else if") accomplishes this. When elif statements are used, the program will go through the if statement. If it evaluates to true, its actions will be performed and then program flow will jump to the first statement after the end of the if block (where fi is located). If it evaluates to false, the first elif is checked. If it is true, the statements inside it are executed and flow jumps to the end of the if block. If it is false, the second elif statement is evaluated, and so on. Basically, evaluations are done until the program reaches an expression that evaluates to true. If none of the conditions evaluate to true, either nothing happens or the statements inside else, if present, are executed. Listing 10.17 uses much of what you have learned up to this point, including if, elif, and else to play a simple number-guessing game. Note that line 10 uses jot, a little command-line random-number-generating tool. The arguments in this case to its r option are the number of results to return (1), the lower bound (1), and the upper bound ($up_limit). Listing 10.17. A Simple Number-Guessing Game
Here's a sample run: Number guessing game written in Bourne shell script. Enter upper limit for guess: 10 I've thought of a number between 1 and 10. Please guess a number between 1 and 10: 5 Your guess was too low. Please try again. Please guess a number between 1 and 10: 8 Your guess was too high. Please try again. Please guess a number between 1 and 10: 7 Correct! You guessed the number in 3 guesses. Most of the concepts in this program should be familiar to you by now:
Like loop tests, if tests also support the logical AND (&&) and logical OR (||) tests to perform actions if and only if both conditions are true, or if one of any number of conditions is true. case StatementsIf you need to test the same variable for multiple conditions, there is a more efficient and cleaner way of doing it than with if statements. The case statement takes a variable as an argument and then uses statement blocks to determine what to do, depending on the value of the variable. Listing 10.18 uses case statements to create a random quote generator. Listing 10.18. Using case to Generate Random Quotes
Once again, you use jot in line 3 to generate a random number between 1 and 4. The case block begins on line 4. The syntax is case variable in, where variable is the name of the variable that the tests should be performed on. Line 5 begins the first test. Everything to the left of the parenthesis indicates the condition that case tests for. Like the if statement, case stops at the first match it comes to, executes the statements that go with that match, and then jumps down to esac (which is "case" spelled backward). The end of the statements that go along with each condition is marked with a double semicolon, which can be on a line by itself, or can be placed on the same line as the last statement, as is done in the previous example. The case statement also accepts shell wildcards. Here's an example: case "$myVar" in a) #statements to do for a ;; b) #statements to do for b ;; *) #statements to do for anything else ;; esac The previous code will check to see whether myVar is equal to a or b, and perform the appropriate statements if it is. If it is not, the last test is a wildcard that will match anything. So, if myVar is not equal to a or b, the last group of statements (for example, printing an error message) will be performed. Other wildcards supported by case include ?, which works the same way it does in the shell (as you saw in Chapter 8), and the pipe character (|), which allows case to accept a range of options. For example, Y | y) will accept either Y or y as a match for a test. You can also enclose multiple characters in brackets to match a range of characters. For example, [Yy]|[Yy][Ee][Ss]) will accept either y or yes as a match in any combination of upper- or lowercase letters.
Logical AND/OR ConditionalsLogical AND/OR conditionals can serve as a shorthand way of doing if statements. They use the exit status of the first command to determine whether to run the second command. Here's an example of a shell command that packs a lot of programming meaning into a single command line: # tar cvfz backup.tar.gz documents/2004/* && rm -r documents/2004 This command basically says, "If the first operation is successful, perform the second operation. If the first operation is not successful, do not perform the second operation." In other words, "You have to perform A and B. If A cannot be performed, do not perform B." In this case, it will attempt to use the tar command to archive all the files in the directory documents/2004 into a file called backup.tar.gz. If the archive operation is successful (the tar command exits with 0), the operation after && will also be performed, which removes the directory documents/2004. If the archive operation is unsuccessful (the tar command exits with some number other than 0), the operation after && will not be performed (obviously, you do not want to remove the directory if you were unable to successfully archive it). The || is the OR operator. It basically says, "If you cannot perform A, perform B. But do not perform B if A is successful." Here is an example: # tar cvfz backup.tar.gz documents/2000/* || echo "Archive operation failed." In this case, if the archive operation is successful (tar exits with 0), the statement after || will not be executed. If, however, the archive operation fails (tar returns an exit status other than 0), the statement after || will be executed, and an error message will be printed to the screen. |