第7章 Tests =========== 每个完整的合理的编程语言都具有条件判断的功能.Bash具有test命令,不同的[]和()操作,和 if/then结构.
7.1 Test结构 ------------ 一个if/then结构可以测试命令的返回值是否为0(因为0表示成功),如果是的话,执行更多命令.
有一个专用命令"["(左中括号,特殊字符).这个命令与test命令等价,但是出于效率上的考虑, 它是一个内建命令.这个命令把它的参数作为比较表达式或是文件测试,并且根据比较的结果, 返回一个退出码.
在版本2.02的Bash中,推出了一个新的[[...]]扩展test命令.因为这种表现形式可能对某些语 言的程序员来说更加熟悉.注意"[["是一个关键字,并不是一个命令.
Bash把[[ $a -lt $b ]]看作一个单独的元素,并且返回一个退出码.
((...))和let...结果也能够返回一个退出码,当它们所测试的算术表达式的结果为非0的时候, 他们的退出码将返回0.这些算术扩展(见第15章)结构被用来做算术比较. 1 let "1<2" returns 0 (as "1<2" expands to "1") 2 (( 0 && 1 )) returns 1 (as "0 && 1" expands to "0")
if命令可以测试任何命令,不仅仅是括号中的条件. 1 if cmp a b &> /dev/null # 阻止输出. 2 then echo "Files a and b are identical." 3 else echo "Files a and b differ." 4 fi 5 6 # 非常有用的"if-grep" 结构: 7 # ------------------------ 8 if grep -q Bash file 9 then echo "File contains at least one occurrence of Bash." 10 fi 11 12 word=Linux 13 letter_sequence=inu 14 if echo "$word" | grep -q "$letter_sequence" 15 # "-q"选项是用来阻止输出 16 then 17 echo "$letter_sequence found in $word" 18 else 19 echo "$letter_sequence not found in $word" 20 fi 21 22 23 if COMMAND_WHOSE_EXIT_STATUS_IS_0_UNLESS_ERROR_OCCURRED 24 then echo "Command succeeded." 25 else echo "Command failed." 26 fi
一个if/then结构可以包含多级比较和tests.
1 if echo "Next *if* is part of the comparison for the first *if*." 2 3 if [[ $comparison = "integer" ]] 4 then (( a < b )) 5 else 6 [[ $a < $b ]] 7 fi 8 9 then 10 echo '$a is less than $b' 11 fi
Example 7-1 什么情况下为真? ################################Start Script####################################### 1 #!/bin/bash 2 3 # 技巧: 4 # 如果你不确定一个特定的条件如何判断. 5 #+ 在一个if-test结构中测试它. 6 7 echo 8 9 echo "Testing \"0\"" 10 if [ 0 ] # zero 11 then 12 echo "0 is true." 13 else 14 echo "0 is false." 15 fi # 0 is true. 16 17 echo 18 19 echo "Testing \"1\"" 20 if [ 1 ] # one 21 then 22 echo "1 is true." 23 else 24 echo "1 is false." 25 fi # 1 is true. 26 27 echo 28 29 echo "Testing \"-1\"" 30 if [ -1 ] # -1 31 then 32 echo "-1 is true." 33 else 34 echo "-1 is false." 35 fi # -1 is true. 36 37 echo 38 39 echo "Testing \"NULL\"" 40 if [ ] # NULL (控状态) 41 then 42 echo "NULL is true." 43 else 44 echo "NULL is false." 45 fi # NULL is false. 46 47 echo 48 49 echo "Testing \"xyz\"" 50 if [ xyz ] # 字符串 51 then 52 echo "Random string is true." 53 else 54 echo "Random string is false." 55 fi # Random string is true. 56 57 echo 58 59 echo "Testing \"\$xyz\"" 60 if [ $xyz ] # 测试$xyz是否为null,但是...(明显没人定义么!) 61 # 只不过是一个未定义的变量 62 then 63 echo "Uninitialized variable is true." 64 else 65 echo "Uninitialized variable is false." 66 fi # Uninitialized variable is false. 67 68 echo 69 70 echo "Testing \"-n \$xyz\"" 71 if [ -n "$xyz" ] # 更学究的的检查 72 then 73 echo "Uninitialized variable is true." 74 else 75 echo "Uninitialized variable is false." 76 fi # Uninitialized variable is false. 77 78 echo 79 80 81 xyz= # 初始化了,但是将其设为空值 82 83 echo "Testing \"-n \$xyz\"" 84 if [ -n "$xyz" ] 85 then 86 echo "Null variable is true." 87 else 88 echo "Null variable is false." 89 fi # Null variable is false. 90 91 92 echo 93 94 95 # 什么时候"flase"为true? 96 97 echo "Testing \"false\"" 98 if [ "false" ] # 看起来"false"只不过是个字符串而已. 99 then 100 echo "\"false\" is true." #+ 并且它test的结果就是true. 101 else 102 echo "\"false\" is false." 103 fi # "false" is true. 104 105 echo 106 107 echo "Testing \"\$false\"" # 再来一个,未声明的变量 108 if [ "$false" ] 109 then 110 echo "\"\$false\" is true." 111 else 112 echo "\"\$false\" is false." 113 fi # "$false" is false. 114 # 现在我们终于得到了期望的结果 115 116 # 如果我们test这个变量"$true"会发生什么结果?答案是和"$flase"一样,都为空,因为我 117 #+ 们并没有定义它. 118 echo 119 120 exit 0 ################################End Script######################################### 练习.解释上边例子的行为(我想我解释的已经够清楚了)
1 if [ condition-true ] 2 then 3 command 1 4 command 2 5 ... 6 else 7 # 可选的(如果不需要可以省去) 8 # 如果原始的条件测试结果是false,那么添加默认的代码来执行. 9 command 3 10 command 4 11 ... 12 fi
注意:当if和then在一个条件测试的同一行中的话,必须使用";"来终止if表达式.if和then都是 关键字.关键字(或者命令)作为一个表达式的开头,并且在一个新的表达式开始之前,必须 结束上一个表达式. 1 if [ -x "$filename" ]; then
Else if和elif
elif elif是else if的缩减形式. 1 if [ condition1 ] 2 then 3 command1 4 command2 5 command3 6 elif [ condition2 ] 7 # Same as else if 8 then 9 command4 10 command5 11 else 12 default-command 13 fi
使用if test condition-true这种形式和if[condition-true]这种形式是等价的.向我们前边 所说的"["是test的标记.并且以"]"结束.在if/test中并不应该这么严厉,但是新版本的Bash 需要它.
注意:test命令是Bash的内建命令,用来测试文件类型和比较字符串.因此,在Bash脚本中,test 并不调用/usr/bin/test的二进制版本(这是sh-utils工具包的一部分).同样的,[并不调用 /usr/bin/[,被连接到/usr/bin/test. bash$ type test test is a shell builtin bash$ type '[' [ is a shell builtin bash$ type '[[' [[ is a shell keyword bash$ type ']]' ]] is a shell keyword bash$ type ']' bash: type: ]: not found
Example 7-2 几个等效命令test,/usr/bin/test,[],和/usr/bin/[ ################################Start Script####################################### 1 #!/bin/bash 2 3 echo 4 5 if test -z "$1" 6 then 7 echo "No command-line arguments." 8 else 9 echo "First command-line argument is $1." 10 fi 11 12 echo 13 14 if /usr/bin/test -z "$1" # 与内建的test结果相同 15 then 16 echo "No command-line arguments." 17 else 18 echo "First command-line argument is $1." 19 fi 20 21 echo 22 23 if [ -z "$1" ] # 与上边代码的作用相同 24 # if [ -z "$1" 应该工作,但是... 25 #+ Bash相应一个缺少关闭中括号的错误消息. 26 then 27 echo "No command-line arguments." 28 else 29 echo "First command-line argument is $1." 30 fi 31 32 echo 33 34 35 if /usr/bin/[ -z "$1" ] # 再来一个,与上边代码的作用相同 36 # if /usr/bin/[ -z "$1" # 工作,但是给个错误消息 37 # # 注意: 38 # This has been fixed in Bash, version 3.x. 38 # 在ver 3.x上,这个bug已经被Bash修正了. 39 then 40 echo "No command-line arguments." 41 else 42 echo "First command-line argument is $1." 43 fi 44 45 echo 46 47 exit 0 ###############################End Script#########################################
[[]]结构比Bash的[]更加灵活,这是一个扩展的test命令,从ksh88继承过来的. 注意:在[[]]结构中,将没有文件扩展或者是单词分离,但是会发生参数扩展和命令替换. 1 file=/etc/passwd 2 3 if [[ -e $file ]] 4 then 5 echo "Password file exists." 6 fi 注意:使用[[]],而不是[],能够阻止脚本中的许多逻辑错误.比如,尽管在[]中将给出一个错误, 但是&&,||,<>操作还是能够工作在一个[[]]test之中. 注意:在if后边,test命令和[]或[[]]都不是必须的.如下: 1 dir=/home/bozo 2 3 if cd "$dir" 2>/dev/null; then # "2>/dev/null" hides error message. 4 echo "Now in $dir." 5 else 6 echo "Can't change to $dir." 7 fi if命令将返回if后边的命令的退出码.
与此相似,当在一个在使用与或列表结构的时候,test或中括号的使用,也并不一定非的有if不可 1 var1=20 2 var2=22 3 [ "$var1" -ne "$var2" ] && echo "$var1 is not equal to $var2" 4 5 home=/home/bozo 6 [ -d "$home" ] || echo "$home directory does not exist."
(())结构扩展并计算一个算术表达式的结果.如果表达式的结果为0,它将返回1作为退出码,或 者是"false".而一个非0表达式的结果将返回0作为退出码,或者是"true".
Example 7-3 算数测试使用(( )) ################################Start Script####################################### 1 #!/bin/bash 2 # 算数测试 3 4 # The (( ... )) construct evaluates and tests numerical expressions. 4 # (( ... ))结构计算并测试算数表达式的结果. 5 # 退出码将与[ ... ]结构相反! 6 7 (( 0 )) 8 echo "Exit status of \"(( 0 ))\" is $?." # 1 9 10 (( 1 )) 11 echo "Exit status of \"(( 1 ))\" is $?." # 0 12 13 (( 5 > 4 )) # true 14 echo "Exit status of \"(( 5 > 4 ))\" is $?." # 0 15 16 (( 5 > 9 )) # false 17 echo "Exit status of \"(( 5 > 9 ))\" is $?." # 1 18 19 (( 5 - 5 )) # 0 20 echo "Exit status of \"(( 5 - 5 ))\" is $?." # 1 21 22 (( 5 / 4 )) # 除法也行 23 echo "Exit status of \"(( 5 / 4 ))\" is $?." # 0 24 25 (( 1 / 2 )) # 出发结果<1 26 echo "Exit status of \"(( 1 / 2 ))\" is $?." # 结果将为0 27 # 1 28 29 (( 1 / 0 )) 2>/dev/null # 除数为0的错误 30 # ^^^^^^^^^^^ 31 echo "Exit status of \"(( 1 / 0 ))\" is $?." # 1 32 33 # What effect does the "2>/dev/null" have? 33 # "2>/dev/null"的作用是什么? 34 # 如果删除"2>dev/null"将会发生什么? 35 # Try removing it, then rerunning the script. 35 # 尝试删除它,然后再运行脚本. 36 37 exit 0 ################################End Script######################################### |