< Day Day Up > |
10.6. Conditional Constructs and Flow ControlWhen making decisions, the if, if/else, if/else if, and switch commands are used. These commands control the flow of the program by allowing decision making based on whether an expression is true or false. 10.6.1 Testing ExpressionsAn expression consists of a set of operands separated by operators. Operators and precedence are listed in Tables 10.5 and 10.6, respectively. To test an expression, the expression is surrounded by parentheses. The C shell evaluates the expression, resulting in either a zero or nonzero numeric value. If the result is nonzero, the expression is true; if the result is zero, the expression is false.
When evaluating an expression with the logical AND (&&), the shell evaluates from left to right. If the first expression (before the &&) is false, the shell assigns false as the result of the entire expression, never checking the remaining expressions. Both expressions surrounding a logical && operator must be true for the entire expression to evaluate to true. ( 5 && 6 ) Expression is true ( 5 && 0 ) Expression is false ( 0 && 3 && 2 ) Expression is false When evaluating an expression with the logical OR (||), if the first expression to the left of the || is true, the shell assigns true to the entire expression and never checks further. In a logical || expression, only one of the expressions must be true. ( 5 || 6 ) Expression is true ( 5 || 0 ) Expression is true ( 0 || 0 ) Expression is false ( 0 || 4 || 2 ) Expression is true The logical NOT is a unary operator; that is, it evaluates one expression. If the expression to the right of the NOT operator is true, the expression becomes false. If it is false, the expression becomes true. ! 5 Expression is false ! 0 Expression is true 10.6.2 Precedence and AssociativityLike C, the C shell uses precedence and associativity rules when testing expressions. If you have an expression with a mix of different operators, such as the following, the shell reads the operators in a certain order: @ x = 5 + 3 * 2 echo $x 11 Precedence refers to the order of importance of the operator. Associativity refers to whether the shell reads the expression from left to right or right to left when the precedence is equal.[2] Other than in arithmetic expressions (which you will not readily need in shell scripts anyway), the order of associativity is from left to right if the precedence is equal. You can change the order by using parentheses. (See Table 10.6.)
@ x = ( 5 + 3 ) * 2 echo $x 16 Expressions can be numeric, relational, or logical. Numeric expressions use the following arithmetic operators: + – * / ++ -- % Relational expressions use the operators that yield either a true (nonzero) or false (zero) result: > < >= <= == != Logical expressions use these operators that also yield true or false: ! && || 10.6.3 The if StatementThe simplest form of conditional is the if statement. After the if expression is tested, and if the expression evaluates to true, the commands after the then keyword are executed until the endif is reached. The endif keyword terminates the block. The if statement may be nested as long as every single if statement is terminated with a matching endif. The endif goes with the nearest enclosing if. FORMAT if ( expression ) then command command endif Example 10.11.(In the Script: Checking for Arguments) 1 if ( $#argv != 1 ) then 2 echo "$0 requires an argument" 3 exit 1 4 endif EXPLANATION
10.6.4 Testing and Unset or Null VariablesThe $? special variable is used to test if a variable has been set. It will return true if the variable is set to some value, including null. Example 10.12.
(From .cshrc/.tcshrc File)
if ( $?prompt ) then
set history = 32
endif
EXPLANATION The .cshrc file is executed every time you start a new csh program. $? is used to check to see if a variable has been set. In this example, the shell checks to see if the prompt has been set. If the prompt is set, you are running an interactive shell, not a script. The prompt is only set for interactive use. Because the history mechanism is only useful when running interactively, the shell will not set history if you are running a script. Example 10.13.
(The Script)
echo -n "What is your name? "
1 set name = $<
2 if ( "$name" != "" ) then
grep "$name" datafile
endif
EXPLANATION
10.6.5 The if/else StatementThe if/else construct is a two-way branching control structure. If the expression following the if is true, the statements following it are executed; otherwise, the statements after the else are executed. The endif matches the innermost if statement and terminates the statement. FORMAT if ( expression ) then command else command endif Example 10.14.1 if ( $answer =~ [Yy]* ) then 2 mail bob < message 3 else 4 mail john < datafil e 5 endif EXPLANATION
10.6.6 Logical ExpressionsThe logical operators are &&, ||, and !. The AND operator, &&, evaluates the expression on the left-hand side of &&; if true, the expression on the right side of && is tested and must also be true. If one expression is false, the expression is false. The OR operator, ||, evaluates the expression on the left-hand side of ||; if true, the expression is true; if false, the expression on the right side of the || operator is tested. If it is true, the expression is true. If both expressions are false, the expression is false. The NOT operator, !, is a unary operator. It evaluates the expression on the right and if that expression is true, it becomes false, and if it is false, it becomes true. If one expression is false, the expression is false. The –x option (called echoing) to the C/TC shell allows you to trace what is going on in your script as it executes. (See Chapter 15, "Debugging Shell Scripts," on page 967.) Example 10.15.(The Script: Using Logical Expressions and Checking Values) #!/bin/csh -f # Scriptname: logical set x = 1 set y = 2 set z = 3 1 if ( ( "$x" && "$y" ) || ! "$z" ) then # Note: grouping and parentheses 2 echo TRUE else echo FALSE endif (The Output) 3 % csh -x logical set x = 1 set y = 2 set z = 3 if ( ( 1 && 2 ) || ! 3 ) then echo TRUE TRUE else % EXPLANATION
10.6.7 The if Statement and a Single CommandIf an expression is followed by a single command, the then and endif keywords are not necessary. FORMAT if ( expression ) single command Example 10.16.
if ($#argv == 0) exit 1
EXPLANATION The expression is tested. If the number of command-line arguments, $#argv, is equal to 0, the program is exited with a status of 1. 10.6.8 The if/else if StatementThe if/else if construct offers a multiway decision-making mechanism. A number of expressions can be tested, and when one of the expressions evaluated is true, the block of statements that follow is executed. If none of the expressions is true, the else block is executed. FORMAT if ( expression ) then command command else if ( expression ) then command command else command endif Example 10.17.(The Script: grade) #!/bin/csh -f # Scriptname: grade echo -n "What was your grade? " set grade = $< 1 if ( $grade >= 90 && $grade <= 100 ) then echo "You got an A\!" 2 else if ( $grade > 79 ) then echo "You got a B" 3 else if ( $grade > 69 ) then echo "You're average" else 4 echo "Better study" 5 endif EXPLANATION
10.6.9 Exit Status and the Status VariableEvery UNIX/Linux command returns an exit status. If the command was successful, it returns an exit status of zero. If the command failed, it returns a nonzero exit status. You can test to see whether the command succeeded or failed by looking at the value of the C shell status variable. The status variable contains the exit status of the last command executed. Example 10.18.1 % grep ellie /etc/passwd ellie:pHAZk66gA:9496:41:Ellie:/home/jody/ellie:/bin/csh 2 % echo $status 0 # Zero shows that grep was a success 3 % grep joe /etc/passwd 4 % echo $status 1 # Nonzero shows that grep failed EXPLANATION
10.6.10 Exiting from a Shell ScriptIn your shell script, the exit command will take you back to the shell prompt. The exit command takes an integer value to indicate the type of exit. A nonzero argument indicates failure; zero indicates success. The number must be between 0 and 255. Example 10.19.(The checkon Shell Script) #!/bin/csh -f 1 if ( $#argv != 1 ) then 2 echo "$0 requires an argument" EXPLANATION
10.6.11 Using an Alias to Create an Error MessageYou may want to create a customized diagnostic message when exiting from a script due to some error condition. This can be accomplished with an alias, as shown in Example 10.20. Example 10.20.(The Script) #!/bin/tcsh -f # Scriptname: filecheck # Usage: filecheck filename 1 alias Usage 'echo " Usage: $0 filename\!*" ; exit 1' 2 alias Error 'echo " Error: \!* "; exit 2' 3 set file=$1 4 if ( $#argv == 0 ) then Usage endif 5 if ( ! -e $file ) then Error "$file does not exist" endif (The Command Line) % filecheck Usage: filecheck filename % echo status 1 % filecheck xyzfile Error: xyzfile does not exist % echo $status 2 10.6.12 Using the Status Variable in a ScriptThe status variable can be used in a script to test the status of a command. The status variable is assigned the value of the last command that was executed. Example 10.21.
(The Script)
#!/bin/csh -f
1 ypmatch $1 passwd >& /dev/null
2 if ( $status == 0 ) then
3 echo Found $1 in the NIS database
endif
EXPLANATION
10.6.13 Evaluating Commands Within ConditionalsThe C shell evaluates expressions in conditionals. To evaluate commands in conditionals, curly braces must enclose the command. If the command is successful, that is, returns an exit status of zero, the curly braces tell the shell to evaluate the expression as true (1).[3] If the command fails, the exit status is nonzero, and the expression is evaluated as false (0).
It is important, when using a command in a conditional, to know the exit status of that command. For example, the grep program returns an exit status of 0 when it finds the pattern it is searching for, 1 when it cannot find the pattern, and 2 when it cannot find the file. When awk or sed are searching for patterns, those programs return 0 whether or not they are successful in the pattern search. The criterion for success with awk and sed is based on whether the syntax is correct; that is, if you typed the command correctly, the exit status of awk and sed is 0. If the exclamation mark is placed before the expression, it NOTs the entire expression so that if true, it is now false, and vice versa. Make sure a space follows the exclamation mark, or the C shell will invoke the history mechanism. FORMAT if { ( command ) } then command command endif Example 10.22.#!/bin/csh -f 1 if { ( who | grep $1 >& /dev/null ) } then 2 echo $1 is logged on and running: 3 ps -ef | grep "^ *$1" # ps –aux for BSD 4 endif EXPLANATION
FORMAT if ! { (command) } then Example 10.23.1 if ! { ( ypmatch $user passwd >& /dev/null ) } then 2 echo $user is not a user here. exit 1 3 endif EXPLANATION
10.6.14 The gotoA goto allows you to jump to some label in the program and start execution at that point. Although gotos are frowned on by many programmers, they are sometimes useful for breaking out of nested loops. Example 10.24.(The Script) #!/bin/csh -f 1 startover: 2 echo "What was your grade? " set grade = $< 3 if ( "$grade" < 0 || "$grade" > 100 ) then 4 echo "Illegal grade" 5 goto startover endif if ( $grade >= 89 ) then echo "A for the genius\!" else if ( $grade >= 79 ) then .. < Program continues > EXPLANATION
10.6.15 File Testing with the C ShellBoth the C and TC shells have a built-in set of options for testing attributes of files, such as whether it is a directory, a plain file (not a directory), a readable file, and so forth. The TC shell adds a few more features in this area, which will be discussed in "File Testing with the TC Shell" on page 551. For other types of file tests, the UNIX/Linux test command is used. The built-in options for file inquiry are listed in Table 10.7. Example 10.25.#!/bin/csh -f 1 if ( –e file ) then echo file exists endif 2 if ( –d file ) then echo file is a directory endif 3 if ( ! –z file ) then echo file is not of zero length endif 4 if ( -r file && -w file ) then echo file is readable and writable endif
EXPLANATION
10.6.16 The test Command and File TestingThe UNIX/Linux test command includes options that were built into the C shell, as well as a number of options that were not. See Table 10.8 for a list of test options. You may need these additional options when testing less common attributes of files such as block and special character files, or setuid files. The test command evaluates an expression and returns an exit status of either 0 for success or 1 for failure. When using the test command in an if conditional statement, curly braces must surround the command so that the shell can evaluate the exit status properly.[4]
Example 10.26.1 if { test –b file } echo file is a block special device file 2 if { test –u file } echo file has the set–user–id bit set
EXPLANATION
10.6.17 Nesting ConditionalsConditional statements can be nested. Every if must have a corresponding endif (else if does not have an endif). It is a good idea to indent nested statements and line up the ifs and endifs so that you can read and test the program more effectively. Example 10.27.(The Script) #!/bin/csh -f # Scriptname: filecheck # Usage: filecheck filename set file=$1 (The Command Line) $ filecheck testing You have read and execute permission of file testing. EXPLANATION
10.6.18 File Testing with the TC ShellThe TC shell, like the C shell, has a built-in set of options for testing attributes of files, such as whether the file is a directory, a plain file (not a directory), a readable file, and so forth. But the TC shell provides additional techniques for file testing as listed below. The operators listed in Table 10.9 return 1 for true and 0 for false after testing an attribute of a file or directory in terms of the real user. The built-in options for file inquiry are listed in Table 10.10 on page 554. The TC shell allows these operators to be bound together (the C shell does not). The form –rwx is the same as –r && –w && –x. Example 10.28.
(The Script)
#!/bin/tcsh -f
# Scriptname: filetest1
1 if ( –e file ) then
echo file exists
endif
2 if ( –d file ) then
echo file is a directory
endif
3 if ( ! –z file ) then
echo file is not of zero length
endif
4 if ( -r file && -w file && -x file) then
echo file is readable and writable and executable.
endif
5 if ( -rwx file ) then
echo file is readable and writable and executable.
endif
EXPLANATION
Example 10.29.(The Script) #!/bin/tcsh -f # Scriptname: filetest2 1 foreach file (`ls`) 2 if ( -rwf $file ) then 3 echo "${file}: readable/writable/plain file" endif end (Output) 3 complete: readable/writable/plain file dirstack: readable/writable/plain file file.sc: readable/writable/plain file filetest: readable/writable/plain file glob: readable/writable/plain file modifiers: readable/writable/plain file env: readable/writable/plain file EXPLANATION
10.6.19 The filetest Built-In (tcsh)The tcsh built-in filetest command applies one of the file inquiry operators to a file or list of files and returns a space-separated list of numbers; 1 for true and 0 for false. Example 10.30.1 > filetest -rwf dirstack file.sc xxx 1 1 0 2 > filetest -b hdd 1 3 > filetest -lrx /dev/fd 1 EXPLANATION
10.6.20 Additional TC Shell File-Testing OperatorsThere is an additional set of file-testing operators (tcsh only), shown in Table 10.10, that return information about files. Because the returned values are not true/false values, a –1 indicates failure (except F , which returns a :). Example 10.31.1 > date Wed Apr 22 13:36:11 PST 2004 2 > filetest -A myfile 934407771 3 > filetest -A: myfile Wed Apr 22 14:42:51 2004 4 > filetest -U myfile 501 5 > filetest -P: myfile 0600 > filetest -P myfile 600 EXPLANATION
Example 10.32.(The Script) #!/bin/tcsh -f # Scriptname: filecheck # Usage: filecheck filename 1 alias Usage 'echo " Usage: $0 filename\!*" ; exit 1' 2 alias Error 'echo " Error: \!* "; exit 2' You have read and execute permission on file testing1. EXPLANATION
10.6.21 The switch CommandThe switch command is an alternative to using the if–then–else if construct. Sometimes the switch command makes a program clearer to read when handling multiple options. The value in the switch expression is matched against the expressions, called labels, following the case keyword. The case labels will accept constant expressions and wildcards. The label is terminated with a colon. The default label is optional, but its action is taken if none of the other cases match the switch expression. The breaksw is used to transfer execution to the endsw. If a breaksw is omitted and a label is matched, any statements below the matched label are executed until either a breaksw or endsw is reached. FORMAT switch (variable) case constant: commands breaksw case constant: commands breaksw endsw Example 10.33.(The Script) #!/bin/csh -f # Scriptname: colors 1 echo -n "Which color do you like? " 2 set color = $< 3 switch ("$color") 4 case bl*: echo I feel $color echo The sky is $color 5 breaksw 6 case red: # Is is red or is it yellow? 7 case yellow: 8 echo The sun is sometimes $color. 9 breaksw 10 default: 11 echo $color is not one of the categories. 12 breaksw 13 endsw (The Command Line) % colors (The Output) 1 Which color do you like? red 8 The sun is sometimes red. 1 Which color do you like? Doesn't matter 11 Doesn't matter is not one of the categories. EXPLANATION
Nesting SwitchesSwitches can be nested; that is, a switch statement and its cases can be contained within another switch statement as one of its cases. There must be an endsw to terminate each switch statement. A default case is not required. Example 10.34.(The Script) #!/bin/csh -f # Scriptname: systype # Program to determine the type of system you are on. echo "Your system type is: " 1 set release = (`uname -r`) 2 switch (`uname -s`) 3 case SunOS: 4 switch ("$release") 5 case 4.*: echo "SunOS $release" breaksw 6 case [5-9].*: echo "Solaris $release" breaksw 7 endsw breaksw case HP*: echo HP-UX breaksw case Linux: echo Linux breaksw 8 endsw (The Output) Your system type: SunOS 4.1.2 EXPLANATION
10.6.22 The here document and MenusThe here document (discussed in "The here document" on page 433) is used in shell scripts to produce a menu. It is often used in conjunction with the switch statement. Once the user has seen the menu, he or she selects an item, and then the choice is matched in the switch statement to the case that corresponds to the choice. The here document reduces the number of echo statements that would otherwise be needed and makes the program easier to read. Example 10.35.(The Script) #! /bin/tcsh 1 echo "Select from the following menu:" 2 cat << EOF 1) Red 2) Green 3) Blue 4) Exit 3 EOF 4 set choice = $< 5 switch ("$choice") 6 case 1: echo Red is stop. 7 breaksw case 2: echo Green is go\! breaksw case 3: echo Blue is a feeling... breaksw case 4: exit breaksw default: echo Not a choice\!\! endsw 8 echo Good-bye (The Output) Select from the following menu: 1) Red 2) Green 3) Blue 4) Exit 2 Green is go! Good-bye EXPLANATION
|
< Day Day Up > |