Comparisons and Tests

5 300 0
Comparisons and Tests

Đang tải... (xem toàn văn)

Thông tin tài liệu

25 ■ ■ ■ CHAPTER 4 Comparisons and Tests T wo of the fundamental types of operations in any programming language are the comparison and the test. They are the building blocks of conditional statements (if/ then and case) and iteration statements (while). They give you the ability to examine relationships between data items, such as files, variables, strings, and numeric values, and to take action based on the result. You can also carry out actions based on the attributes of a particular item, such as a file’s type, whether a variable has been assigned a value, and the return code of a command. The examples in this chapter illustrate various ways to compare items or to check their properties, and use the results. I have used all of these techniques throughout this book, although some are used more frequently than others. Here I want to present a diverse set of examples that demonstrate the many uses of the test shell programming structure. The Basics of Comparisons In UNIX shell scripting there are both internal operators that allow you to test attributes or to compare values, and a /usr/bin/test system call. Please refer to Appendix A for more specific information. The following two comparison examples are among the most common forms: if [ "$string" = "some_string" ];then . if [ $integer -eq 15 ];then . The first example represents a string comparison and the second an integer test. The quotation marks are required only for an explicit string. Quotation marks around the name of a string variable are not required. It is wise, however, to always quote your string variables to gracefully handle an undefined variable or white space within the string. A comparison involving an unquoted, undefined string variable in the bash shell will return a “unary operator expected” error, whereas ksh will return an “argu- ment expected” message. A comparison involving an unquoted string that contains white space will result in a “too many arguments” error in bash and an “unknown oper- ator” in ksh. All of these errors are related to the test command finding that there are too few or too many arguments in the comparison—too few because an unquoted null 26 CHAPTER 4 ■ COMPARISONS AND TESTS variable is skipped over in the comparison, and too many because an unquoted string containing white space will be viewed as more than one argument instead of a single string. The spaces between the values being compared and the square brackets are required syntax, but the spaces between the values being compared and the comparison operator are optional. Note that the operators for string and numeric comparison are the opposite of what you might expect. To my mind, the equal sign (=) implies a numeric comparison and the -eq operator suggests a string operation, but this is not the case. The other conditional operators mirror this distinction. The operators =, !=, >, and < used for string comparisons are direct counterparts to the numeric comparison operators -eq, -ne, -gt, and -lt. There are still more operators that can be found in both the test man page and the man pages for specific shells. The square brackets in the previous examples contain the enclosed expressions to cre- ate a statement that represents the logical result (true or false) of the test described by the enclosed expressions. To be more accurate, the left square bracket ([) is both a command internal to the shell and a system command (/usr/bin/[) that can be thought of the same as the test command. The [ command has specific syntax that must be followed; for instance, the comparison is completed with a closing right square bracket (]), and this command’s return code determines if the comparison is true. In the following example, the square brackets have been replaced with the test command to illustrate another method of forming a comparison statement. The square brackets can be used inter- changeably with the test command. if test $string = "some_string" ;then . All examples so far have used the if/then structure for comparing values. Usually, if the expression given to the test command or enclosed in the square brackets evaluates to true, then we perform some task. The syntax of this example is slightly different. In this code pattern, the test on the left of the && operator is performed as in previous compari- son examples and based on the result (true or false); the code on the right is executed or skipped. Here, if the debug variable is set to 1, the left-hand expression evaluates to true and the echo command will be run. The line of code can also be read as “test the condi- tion AND execute the additional code if the test evaluates as true.” test $debug -eq 1 && echo some_debug_output An alternative is available. If the logical AND (&&) is replaced with a logical OR (||), the additional code is executed only if the test returns false. This example can be read as “test the condition OR execute the additional code (if the test evaluates as false).” test $debug -eq 1 || echo some_debug_output CHAPTER 4 ■ COMPARISONS AND TESTS 27 Both the logical AND (&&) and logical OR (||) sequences are simply shortcut versions of the more verbose syntax presented here. test $debug -eq 1 && { echo some_debug_output echo some_more_debug_output } In both of the previous examples, the additional code following the logical AND or OR to be run was a single command. Compound commands can be formed by surrounding the individual commands with curly braces. Such groupings can contain any amount of code, including output statements, control structures, assignments, or all of the above. As you’ve seen before, the test command can be replaced with square brackets; the two forms of syntax are equivalent. This segment of code evaluates the expression within the square brackets and runs the compound statement if the expression evalu- ates as true. I have not noticed any significant performance differences between these two syntax types. [ $debug -eq 1 ] && { echo some_debug_output echo some_more_debug_output } Conditional logic can become quite complex. The following example demonstrates two test expressions that must each evaluate as true before the additional code will run. In this case, the logical AND (&&) characters are used to perform two separate functions. The first instance of && is used to require both the first and second expressions to be true. The second instance is used to indicate the additional code that should be run if they both evaluate as true. The use of a logical OR (||) in both places is also valid, and specifies that both of the tests would need to be false to execute the additional code. [ "$txt" ] && [ "$txt" != "$txt2" ] && some_text="$txt $txt2" The following example adds another layer of complexity to the previous example. Not only are there two expressions to evaluate, but the first expression of the two contains two additional expressions of its own. Note that the two main expressions are surrounded by square brackets and are separated by a logical OR (||). The use of the OR indicates that the entire test evaluates as true whenever either one of the two expressions is true. The -a operator inside the first expression is also a logical AND. You can string multiple expres- sions together with the -a or the logical OR (-o) operator, as you can with the && and || syntax. if [ "$txt" != "$txt2" -a $num -eq $num2 ] || [ $num2 -eq 100 ];then . 28 CHAPTER 4 ■ COMPARISONS AND TESTS When such expressions become very complex, it is easy to make logic mistakes that can be difficult to track down. In the following examples, the complexity has been toned down. if [ -n $string ];then . if [ $any_variable ];then . You can use this code to determine whether variables have been defined. The first example of the two applies to string variables, since the -n operation evaluates to true if the length of the supplied string variable is nonzero. However, this method also works for determining whether a numeric variable has been defined, as its value is then treated as a string. The second example simply tests a variable. Once the variable has been assigned a value, the expression will evaluate to true. Thus, both expressions determine if a variable has been assigned a value. The following expressions are similar to the previous ones; they determine if a variable is undefined: if [ -z $string ];then . if [ ! $any_variable ];then . These conditional statements are simply the negations of the corresponding expres- sions in the previous examples (-z tests whether a string has zero length, and ! is the logical NOT symbol). The next example uses a couple of features, one of which we have already seen. if [ "`grep nodename /etc/hosts`" ];then . The test here evaluates to true if the quoted expression is not null. You saw one exam- ple of this earlier, in connection with quoted string variables. In this case, however, you are not looking at the value of a variable, but rather running an external command, and you’re capturing its output to be tested within the square brackets as if it were a string. An expression enclosed in reverse single quotes (`) is evaluated by the shell and substituted with the resulting output. Here, if the grep command returns a match from /etc/hosts, then there is output and the test evaluates as true because the quoted expression is non- null. If grep returns nothing, the quoted expression would then be null and the test would evaluate as false. A test can be performed on more than just a variable or a value, such as a number or a string. In the following example, the test examines the return code of a command: if ping -c 3 node.mydomain.com > /dev/null 2>&1;then As I mentioned earlier, all of these comparisons are really commands that have their return code evaluated. If the command returns a 0 code (indicating successful termina- tion), its execution, in the context of a test, evaluates as true. You can take advantage of this with the ping command, as shown here, because you don’t need to know the actual output of the command to determine whether a system is responsive, which is why all the CHAPTER 4 ■ COMPARISONS AND TESTS 29 output is being redirected to /dev/null. The return code will tell you that. If a system is unresponsive to a ping, the return code will be nonzero. This is a much simpler method than retrieving and analyzing the output of the command. The last example uses the -l switch to the test system command. /usr/bin/test -l "hello" -gt 4 && echo some_message Here you are testing if the length of the string hello is greater than 4. If it is, the code will echo a message. I have included this example because the syntax for this switch is not obvious from the test man page. There is a brief comment about the -l switch, and no example. This example also emphasizes that there is both an internal shell test command and a system test command. The internal test is called unless the system command is specified using the executable’s fully qualified filename (including the path). If you don’t specify the full path to the system test as shown here, the shell’s internal test will return a “unary operator expected” error if you run bash. An “unknown operator” error will appear using ksh. Neither shell’s internal test command uses the -l switch to specify a length comparison. . is both a command internal to the shell and a system command (/usr/bin/[) that can be thought of the same as the test command. The [ command has specific. $debug -eq 1 || echo some_debug_output CHAPTER 4 ■ COMPARISONS AND TESTS 27 Both the logical AND (&&) and logical OR (||) sequences are simply shortcut

Ngày đăng: 05/10/2013, 08:51

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan