"与列表(and list)"和"或列表(or list)" 结构提供一种处理一串连续命令的方法. 它们能有效地替代复杂的嵌套if/then语句甚至可以代替case语句.
1 command-1 && command-2 && command-3 && ... command-n |
例子 25-1. 使用"与列表(and list)"来测试命令行参数
1 #!/bin/bash 2 # "and list" 3 4 if [ ! -z "$1" ] && echo "Argument #1 = $1" && [ ! -z "$2" ] && echo "Argument #2 = $2" 5 then 6 echo "At least 2 arguments passed to script." 7 # 所有连接起来的命令都返回真. 8 else 9 echo "Less than 2 arguments passed to script." 10 # 整个命令列表中至少有一个命令返回假值. 11 fi 12 # 注意"if [ ! -z $1 ]" 可以工作,但它是有所假定的等价物, 13 # if [ -n $1 ] 不会工作. 14 # 但是, 加引用可以让它工作. 15 # if [ -n "$1" ] 就可以了. 16 # 小心! 17 # 最好总是引起要测试的变量. 18 19 20 # 这是使用"纯粹"的 if/then 语句完成的同等功能. 21 if [ ! -z "$1" ] 22 then 23 echo "Argument #1 = $1" 24 fi 25 if [ ! -z "$2" ] 26 then 27 echo "Argument #2 = $2" 28 echo "At least 2 arguments passed to script." 29 else 30 echo "Less than 2 arguments passed to script." 31 fi 32 # 这会更长且不如"与列表"精致. 33 34 35 exit 0 |
例子 25-2. 用"与列表"的另一个命令行参数测试
1 #!/bin/bash 2 3 ARGS=1 # 期望的参数个数. 4 E_BADARGS=65 # 如果用户给出不正确的参数个数的退出码. 5 6 test $# -ne $ARGS && echo "Usage: `basename $0` $ARGS argument(s)" && exit $E_BADARGS 7 # 如果 条件1 测试为真(表示传给脚本的参数不对), 8 #+ 则余下的命令会被执行,并且脚本结束运行. 9 10 # 下面的代码只有当上面的测试失败时才会执行. 11 echo "Correct number of arguments passed to this script." 12 13 exit 0 14 15 # 为了检查退出码,脚本结束后用"echo $?"来查看退出码. |
当然,一个与列表也能给变量设置默认值.
1 arg1=$@ # 不管怎样,设置变量$arg1为命令行参数. 2 3 [ -z "$arg1" ] && arg1=DEFAULT 4 # 如果没有在命令行上指定参数则把$arg1设置为DEFAULT. |
1 command-1 || command-2 || command-3 || ... command-n |
例子 25-3. "或列表"和"与列表"的结合使用
1 #!/bin/bash 2 3 # delete.sh, 不是很聪明的文件删除功能. 4 # 用法: delete filename 5 6 E_BADARGS=65 7 8 if [ -z "$1" ] 9 then 10 echo "Usage: `basename $0` filename" 11 exit $E_BADARGS # 没有参数? 跳出脚本. 12 else 13 file=$1 # 设置文件名. 14 fi 15 16 17 [ ! -f "$file" ] && echo "File \"$file\" not found. \ 18 Cowardly refusing to delete a nonexistent file." 19 # 与列表, 用于文件不存在时给出一个错误信息. 20 # 注意 echo 命令的参数用了一个转义符继续使第二行也是这个命令的参数. 21 22 [ ! -f "$file" ] || (rm -f $file; echo "File \"$file\" deleted.") 23 # 或列表, 用于存在文件时删除此文件. 24 25 # 注意上面两个相反的逻辑. 26 # 与列表为真时才执行, 或列表为假时执行. 27 28 exit 0 |
如果在与列表的第一个命令返回真时,它会执行. |
1 # ==> 下面的片断摘自Miquel van Smoorenburg写的 /etc/rc.d/init.d/single 脚本 2 #+==> 示例与和或列表的使用. 3 # ==> "箭头"的注释由本书作者添加. 4 5 [ -x /usr/bin/clear ] && /usr/bin/clear 6 # ==> 如果 /usr/bin/clear 存在, 则调用它. 7 # ==> 在调用一个命令前检查它是否存在, 8 #+==> 以避免产生错误信息和其他难读懂的结果. 9 10 # ==> . . . 11 12 # 如果他们想在单用户模式下运行某些程序, 可能也会运行这个... 13 for i in /etc/rc1.d/S[0-9][0-9]* ; do 14 # 检查脚本是否可执行. 15 [ -x "$i" ] || continue 16 # ==> 如果在目录$PWD中相应的文件没有发现, 17 #+==> 则会跳过此次循环. 18 19 # 不接受备份文件和由rpm产生的文件. 20 case "$1" in 21 *.rpmsave|*.rpmorig|*.rpmnew|*~|*.orig) 22 continue;; 23 esac 24 [ "$i" = "/etc/rc1.d/S00single" ] && continue 25 # ==> 设置脚本名,但还不执行它. 26 $i start 27 done 28 29 # ==> . . . |
与列表或是或列表的退出状态是最后一个执行命令的退出状态. |
灵活地组合"与"和"或"列表是允许的,但这样逻辑会很容易变得费解并且需要较多的测试.
1 false && true || echo false # false 2 3 # 结果等同 4 ( false && true ) || echo false # false 5 # 但不同与 6 false && ( true || echo false ) # (没有输出) 7 8 # 注意是从左到右来分组并求值的, 9 #+ 因为逻辑操作符"&&"和"||"有相同的优先处理权. 10 11 # 最好避免这种复杂,除非你确实知道你在做什么. 12 13 # Thanks, S.C. |