Shell笔记3——脚本的条件测试与比较

本文档主要讲解Shell变量的数值计算与实践

基本大纲:

  • 1.Shell脚本的条件测试

  • 2.文件测试表达式

  • 3.字符串测试表达式

  • 4.整数二元比较操作符

  • 5.逻辑操作符

  • 6.测试表达式test、[]、[[]]、(())的区别总结




一:shell脚本的条件测试

 1)条件测试方法综述 

  通常,在bash的各种条件结构和流程控制结构中都要进行各种测试,然后根据测试结构执行不同的操作,有时也会与if等条件语句相结合,来完成测试判断,以减少程序运行的错误。

执行条件测试表达式后通常会返回"真"或"假",就像执行命令后返回的值为0表示真,非0表示假一样。

Bash编程中条件测试常用的语法:

     

  条件测试语法

                                       

                                 说明


语法一:test<测试表达式>


这是利用test命令进行测试表达式的方法。test命令和"<测试表达式>"之间至少有一个空格;


语法二:[<测试表达式>]


这是通过[](单中括号)进行条件测试表达式的方法,和test命令的用法相同。[]的边界和内容之间至少有一个空格;


语法三:[[<测试表达式>]]


这是通过[[]](双中括号)进行条件测试表达式的方法。是比test和[]更新的语法格式。[[]]的边界和内容之间至少有一个空格;


语法四:((<测试表达式>))


这是通过(())(双小括号)进行条件测试表达式的方法,一般用于if语句里。(())(双小括号)两端不需要有空格;一般都少用到

针对上表格有几个注意事项需要说明下:

  • 语法一中的test命令和语法二中的[]是等价的。语法三种的[[]]为扩展的test命令,语法四中的(())常用语计算,建议使用相对友好的语法二,即中括号[]的语法格式。

  • 在[[]]中可以使用通配符等进行模式匹配,这是区别于其他几种语法格式的地方。

  • &&、||、>、<\等操作符可以应用于[[]]中,但不能应用于[]中,在[]中一般用-a、-o、-gt(用于整数)、-lt(用于整数)代替上述操作符。

  • 对于整数的关系运算,也可以使用shell的算数运算符(())。

2)语法一:test条件测试的语法及示例

test <测试表达式>
test -f file && echo true || echo false 
#该语句表示如果file存在,则输出true,否则(||)输出false。这里的&&是并且的意思。test的-f参数用于测试文件是否为普通文件,test命令若执行成功(为真),则执行&&后面的命令,
如果执行失败,则执行||后面的命令

范例1:在test命令中使用-f选项测试文件是否存在
[root@aliyun tj]# test -f file && echo true || echo false 
false
[root@aliyun tj]# touch file
[root@aliyun tj]# test -f file && echo true || echo false 
true

范例2:在test命令中使用-z选项测试字符串长度,为0则表达式成立
[root@aliyun tj]# test -z "ywxi" && echo 1 || echo 0        #字符串长度不为0,所以表达式为假,返回结果为0
0
[root@aliyun tj]# char="ywxi"
[root@aliyun tj]# test -z "$char" && echo 1 || echo 0
0
[root@aliyun tj]# char=""    
[root@aliyun tj]# test -z "$char" && echo 1 || echo 0
1


3)语法二:中括号[]条件测试语法及示例

[]条件测试的语法格式为[<测试表达式>]
[ -f file ] && echo true || echo false
#注意:中括号内部的两端要有空格,[]和test等价,即test的所有判断选项都可以直接[]里使用。

范例1:利用[]加-f选项(文件存在且为普通文件则表达式成立)测试文件。
[root@aliyun tj]# [ -f /tmp/file.txt ] && echo true || echo false        #文件不存在,所以输出false
false
[root@aliyun tj]# touch /tmp/file.txt
[root@aliyun tj]# [ -f /tmp/file.txt ] && echo true || echo false        #文件存在,所有输出true
true
[root@aliyun tj]# [ -f /tmp/file.txt ] && echo true 
true
[root@aliyun tj]# [ -f /tmp/file.txt ] || echo false
[root@aliyun tj]# [ -f /tmp/file ] || echo false             #文件不存在,所以不成立,所以执行||后面的输出
false


4)语法三:[[]]条件测试语法及示例

[[]]条件测试的语法格式为:[[<测试表达式>]]
#注意:双中括号里的两端也要有空格。
#[[]]和[]与test的主要区别在于,在[[]]中可以使用通配符等进行模式匹配;并且&&、||、>、<等操作符可以应用在[[]]中,但不能应用在[]中,在[]中一般使用-a、-o、-gt等来代替
范例1:
[root@aliyun tj]# [[ -f /tmp/file.txt ]] && echo true || echo false 
true
[root@aliyun tj]# [[ -f /tmp/test.txt ]] && echo true || echo false     
false
[root@aliyun tj]# touch /tmp/test.txt
[root@aliyun tj]# [[ -f /tmp/test.txt ]] && echo true || echo false 
true
[root@aliyun tj]# rm -rf /tmp/test.txt 
[root@aliyun tj]# [[ -f /tmp/test.txt ]] && echo true || echo false
false




二:文件测试表达式

1)文件测试表达式的用法如下表;


 

  常用文件测试操作符

                                       

                                说明


-d文件,d的全拼为directory


  文件存在且为目录则为真,即测试表达式成立;


-f文件,f的全拼为file


  文件存在且为普通文件则为真,即测试表达式成立;


-e文件,e的全拼为exist


  文件存在则为真,即测试表达式成立。区别于"-f","-e"不能辨别是目录还是文件;


-r文件,r的全拼为read


  文件存在且可读测试为真,即测试表达式成立;


-s文件,s的全拼为size


  文件存在且文件大小不为0则为真,即测试表达式成立;


-w文件,w的全拼为write


  文件存在则可写为真,即测试表达式成立;


-x文件,x的全拼为executable


  文件存在且可执行为真,即测试表达式成立;


-L文件,L的全拼为link


  文件存在且链接文件则为真,即测试表达式成立;


f1 -nt f2,nt的全拼为newer than


  文件f1比文件f2新则为真,即测试表达式成立。根据文件的修改时间来计算;


f1 -ot f2,nt的全拼为older than


  文件f1比文件f2旧则为真,即测试表达式成立。根据文件的修改时间来计算;



2)普通文件和目录测试表达式示例:

[root@aliyun tj]# touch ywxi.txt
[root@aliyun tj]# ls -l ywxi.txt 
-rw-r--r-- 1 root root 0 May 31 13:59 ywxi.txt
[root@aliyun tj]# [ -f ywxi.txt ] && echo 1 || echo 0        #文件存在,表达式成立,输出为1
1
[root@aliyun tj]# mkdir ywxi
[root@aliyun tj]# ls -ld ywxi
drwxr-xr-x 2 root root 4096 May 31 14:02 ywxi
[root@aliyun tj]# [ -f ywxi ] && echo 1 || echo 0        #-f判断文件,ywxi是目录名,所有表达式不成立,则输出为0
0
[root@aliyun tj]# [ -d ywxi ] && echo 1 || echo 0 
1
[root@aliyun tj]# [ -d ywxi.txt ] && echo 1 || echo 0
0
[root@aliyun tj]# [ -e ywxi ] && echo 1 || echo 0         #不区别目录和文件,存在即为表达式成立,输出为1
1
[root@aliyun tj]# [ -e ywxi.txt ] && echo 1 || echo 0
1


3)文件属性测试示例:

[root@aliyun tj]# ls -l ywxi.txt 
-rw-r--r-- 1 root root 0 May 31 13:59 ywxi.txt
[root@aliyun tj]# [ -r ywxi.txt ] && echo 1 || echo 0
1
[root@aliyun tj]# [ -w ywxi.txt ] && echo 1 || echo 0 
1
[root@aliyun tj]# [ -x ywxi.txt ] && echo 1 || echo 0 
0
[root@aliyun tj]# chmod 001 ywxi.txt 
[root@aliyun tj]# ls -l ywxi.txt 
---------x 1 root root 0 May 31 13:59 ywxi.txt
[root@aliyun tj]# [ -w ywxi.txt ] && echo 1 || echo 0        #用户权限位没w,输出1是因为root用户确实可以写。这是root用户特殊的地方
1
[root@aliyun tj]# echo 'echo test' >ywxi.txt 
[root@aliyun tj]# [ -r ywxi.txt ] && echo 1 || echo 0        #用户权限位没r,输出1是因为root用户确实可以读 。这是root用户特殊的地方
1
[root@aliyun tj]# cat ywxi.txt 
test
[root@aliyun tj]# [ -x ywxi.txt ] && echo 1 || echo 0        
1
[root@aliyun tj]# ./ywxi.txt
test
注意:测试文件的读、写、执行等属性,不光是根据文件属性rwx的标识来判断,还要看当前执行测试的用户是否真的可以按照对应的权限操作该文件。


4)测试Shell变量示例

[root@aliyun tj]# ls -la
drwxr-xr-x 2 root root 4096 May 31 14:02 ywxi        #目录
---------x 1 root root   10 May 31 16:41 ywxi.txt    #文件
[root@aliyun tj]# file1=/scripts/practice/tj/ywxi ; file2=/scripts/practice/tj/ywxi.txt
[root@aliyun tj]# echo $file1 $file2
/scripts/practice/tj/ywxi /scripts/practice/tj/ywxi.txt

#对目录测试
[root@aliyun tj]# [ -f "$file1" ] && echo 1 || echo 0    #不是文件,所以为假
0
[root@aliyun tj]# [ -d "$file1" ] && echo 1 || echo 0    #是目录,所以为真
1
[root@aliyun tj]# [ -s "$file1" ] && echo 1 || echo 0    #目录存在且大小不为0,所以为真
1
[root@aliyun tj]# [ -e "$file1" ] && echo 1 || echo 0    #目录存在即为真
1

#对文件测试
[root@aliyun tj]# [ -f "$file2" ] && echo 1 || echo 0    #是文件,所以为真
1
[root@aliyun tj]# [ -d "$file2" ] && echo 1 || echo 0    #不是目录,所以为假
0
[root@aliyun tj]# [ -e "$file2" ] && echo 1 || echo 0    #文件存在,所以为真
1
[root@aliyun tj]# [ -s "$file2" ] && echo 1 || echo 0    #文件存在且大小不为0,所以为真
1

#测试变量的特殊写法及问题
[root@aliyun tj]# echo $ywxi        #变量为空

[root@aliyun tj]# [ -f $ywxi ] && echo 1 || echo 0    #变量不存在,但还返回1,逻辑就不对了
1
[root@aliyun tj]# [ -f "$ywxi" ] && echo 1 || echo 0    #变量加上双引号,逻辑就对了
0

#对于文件实在路径,双引号加与不加就没区别了
[root@aliyun tj]# [ -f /etc/services ] && echo 1 || echo 0
1
[root@aliyun tj]# [ -f "/etc/services" ] && echo 1 || echo 0
1

#在生产环境中,系统NFS启动脚本的条件测试
[root@localhost practice]# grep '&&' /etc/init.d/nfs|head -2
[ -f /etc/sysconfig/network ] &&  . /etc/sysconfig/network        #如果/etc/sysconfig/network文件存在,则加载文件,不用加双引
[ -f /etc/sysconfig/nfs ] && . /etc/sysconfig/nfs             #如果/etc/sysconfig/nfs文件存在,则加载文件,不用加双引




三:字符串测试表达式

1)字符测试表达式

字符串测试操作符的作用包括;比较两个字符串是否相同、测试字符串的长度是否为零,字符串是否为NULL等;


常用字符串测试操作符


                                       说明

 

        -n"字符串"

  若字符串的长度不为0,则为真,即测试表达式成立,n可以理解为no zero;


         -z"字符串"

  若字符串的长度为0,则为真,即测试表达式成立,z可以理解为zero的缩写;


       "串1"= "串2"

  若字符串1等于字符串2,则为真,即测试表达式成立,可以用"=="代替"=";


      "串1"!="串2"

  若字符串1不等于字符串2,则为真,即测试表达式成立,但不能用"!=="代替"!=";

以下是针对字符串测试操作符的提示:

  • 对于字符串的测试,一定要将字符串加双引号之后在进行比较。如[-n $myvar],特别是使用[]的场景;

  • 比较符号(例如=和!=)的两端一定要有空格;

  • "!="和"="可用于比较两个字符串是否相同;


2)字符串条件表达式测试实践:

[root@localhost practice]# [ -n "a" ] && echo 1 || echo 0    #长度不为0,所以为真
1
[root@localhost practice]# test -n "a"  && echo 1 || echo 0    
1
[root@localhost practice]# test -n ""  && echo 1 || echo 0     #长度为0,所以为假
0
[root@localhost practice]# [ -n "" ] && echo 1 || echo 0   
0
[root@localhost practice]# a=ywxi
[root@localhost practice]# echo $a
ywxi
[root@localhost practice]# [ -n "$a" ] && echo 1 || echo 0    #长度不为0,所以为真
1
[root@localhost practice]# [ -n $a ] && echo 1 || echo 0  
1
[root@localhost practice]# [ -z $a ] && echo 1 || echo 0 
0
[root@localhost practice]# [ -z "$a" ] && echo 1 || echo 0
0
[root@localhost practice]# [ "abc" = "abd" ] && echo 1 || echo 0    #字符串不一致,所以为假
0
[root@localhost practice]# [ "abc" = "abc" ] && echo 1 || echo 0 
1
[root@localhost practice]# [ "$a" = "ywxi" ] && echo 1 || echo 0    #解析了变量的值与ywxi一致     
1
[root@localhost practice]# [ $a = "ywxi" ] && echo 1 || echo 0        #解析了变量的值与ywxi一致  
1
[root@localhost practice]# [ '$a' = "ywxi" ] && echo 1 || echo 0                    #原样输出,没解析了变量的值,不与ywxi一致,所以为假
0
[root@localhost practice]# [ "$a" != "ywxi" ] && echo 1 || echo 0                   #解析了$a的值与ywxi一致,是相等的。不等于不成立,所以为假
0


3)字符串测试生产案例:

[root@aliyun tj]# sed -n '30,31p' /etc/init.d/network         #这是系统网卡启动脚本
# Check that networking is up.
[ "${NETWORKING}" = "no" ] && exit 6    #字符串变量和字符串都加了双引号,比较符号"="两端也都有空格




四:整数二元比较操作符 

1)整数二元比较操作符介绍


在[]以及test中使用的比较符号


在(())和[[]]中使用的比较符号


                说明


               -eq


              ==或=


     相等,全拼为equal


               -ne


                !=


  不相等,全拼为not equal


               -gt

             

                >


  大于,全拼为gerater than

          

               -ge


               >=

 大于等于,全拼为gerater equal


               -lt


               <

  

  小于,全拼为less than


              -le


              <=


小于等于,全拼为less equal

以下是针对上述符号的特别说明:

  • "="和"!="也可以在[]中作比较使用,但在[]中使用包含">"和"<"的符号时,需要用反斜线转义,有时不转义虽然语法不会报错,但是结果可能会不对;

  • 也可以在[[]]中使用包含"-gt"和"-lt"的符号,但是不建议这样使用;

  • 比较符号两端也要有空格;


2)二元数字在[]中使用"<"和">"非标准符号的比较

[root@aliyun tj]# [ 2 > 1 ] && echo 1 || echo 0
1
[root@aliyun tj]# [ 2 < 1 ] && echo 1 || echo 0     #2<1的结果1逻辑是不对的,应该返回0才是正常的
1
[root@aliyun tj]# [ 2 \< 1 ] && echo 1 || echo 0    #用\转义后结果逻辑就正常了
0
[root@aliyun tj]# [ 2 = 1 ] && echo 1 || echo 0   
0
[root@aliyun tj]# [ 2 = 2 ] && echo 1 || echo 0 
1
[root@aliyun tj]# [ 2 != 2 ] && echo 1 || echo 0
0


3)二元数字在[]中使用-gt、-le类符号的比较

[root@aliyun tj]# [ 2 -gt 1 ] && echo 1 || echo 0    
1
[root@aliyun tj]# [ 2 -ge 1 ] && echo 1 || echo 0 
1
[root@aliyun tj]# [ 2 -le 1 ] && echo 1 || echo 0 
0
[root@aliyun tj]# [ 2 -lt 1 ] && echo 1 || echo 0 
0

 

4)二元数字配合不同种类的操作符在[[]]中的比较

[root@aliyun tj]# [[ 1 > 2 ]] && echo 1 || echo 0    
0
[root@aliyun tj]# [[ 1 < 2 ]] && echo 1 || echo 0 
1
[root@aliyun tj]# [[ 1 = 2 ]] && echo 1 || echo 0 
0
[root@aliyun tj]# [[ 1 != 2 ]] && echo 1 || echo 0
1
[root@aliyun tj]# [[ 1 -gt 2 ]] && echo 1 || echo 0    
0
[root@aliyun tj]# [[ 1 -lt 2 ]] && echo 1 || echo 0 
1
[root@aliyun tj]# [[ 1 -ne 2 ]] && echo 1 || echo 0  
1
[root@aliyun tj]# [[ 1 -eq 2 ]] && echo 1 || echo 0  
0


5)二元数字在(( ))中的比较

[root@aliyun tj]# ((2>1)) && echo 1 || echo 0
1
[root@aliyun tj]# ((2<1)) && echo 1 || echo 0 
0
[root@aliyun tj]# ((2==1)) && echo 1 || echo 0 
0
[root@aliyun tj]# ((2!==1)) && echo 1 || echo 0
-bash: ((: 2!==1: syntax error: operand expected (error token is "=1")        #"!=="符号不可用,语法错误
0
[root@aliyun tj]# ((2!=1)) && echo 1 || echo 0 
1


有关[]、[[]]、(())用法的小结:

  • 证书加双引号的比较是对的

  • [[]]中用类似-eq等的写法是对的,[[]]中用类似>、<的写法也可能不对,有可能会只比较第一位,逻辑结果不对

  • []中用类似>、<的写法在语法上虽然可能没错,但逻辑结果不对,可以使用=、!=正确比较

  • (())中不能用类似-eq等的写法,可以使用类似>、<的写法




五:逻辑操作符

1)逻辑操作符介绍

在[]和test中使用的操作符


在[[]]和(())中使用的操作符


                说明


           -a


               &&

and,与,两端都为真,则结果为真


           -o


                ||

or,或,两端有一个为真,则结果为真


            !


                 !

Not,非,两端相反,则结果为真

对于上述操作符,有如下提示:

  • 逻辑操作符前后的表达式是否成立,一般用真假来表示;

  • "!"的中文意思是反,即与一个逻辑值相反的逻辑值;

  • -a的中文意思是"与"(and或&&),前后两个逻辑值都为"真",综合返回值才为"真",反之为"假";

  • -o的中文意思是"或"(or或||),前后2个逻辑值只要有一个为"真",返回值就为"真";

  • 连接两含[]、test或[[]]的表达式可用&&或||;


2)逻辑操作符实践示例:

1.[]里的逻辑操作符配合文件测试表达式使用的示例

[root@aliyun tj]# f1=/etc/rc.local ;f2=/etc/services 
[root@aliyun tj]# echo $f1 $f2
/etc/rc.local /etc/services
[root@aliyun tj]# [ -f "$f1" -a -f "$f2" ] && echo 1 || echo 0         #测试f1和f2两个变量是否都为文件,成立则输出1
1
[root@aliyun tj]# [ -f "$f1" -o -f "$f2" ] && echo 1 || echo 0         #测试f1和f2两个变量有一个是否为文件,成立则输出1
1
[root@aliyun tj]# [ -f "$f1" && -f "$f2" ] && echo 1 || echo 0         #&&这是错误语法的提示
-bash: [: missing `]'
0
[root@aliyun tj]# [ -f "$f1" ] && [ -f "$f2" ] && echo 1 || echo 0     #正确运用写法
1


2.[[]]里的逻辑操作符配合字符串的条件表达式使用的示例

[root@aliyun tj]# a="abc";b="def"
[root@aliyun tj]# echo -ne "$a $b\n"
abc def
[root@aliyun tj]# [[ ! -n "$a" && "$a" = "$b" ]] && echo 1 || echo 0     #$a长度不为0并且$a等于$b是否成立,必须两个表达式同时成立 
0
[root@aliyun tj]# [[ -z "$a" -o "$a" != "$b" ]] && echo 1 || echo 0      #内部用-a或-o会报错
-bash: syntax error in conditional expression
-bash: syntax error near `-o'
[root@aliyun tj]# [[ -z "$a" || "$a" != "$b" ]] && echo 1 || echo 0      
1


3.(())逻辑操作符配合整数的条件表达式测试示例

[root@aliyun tj]# m=20;n=30
[root@aliyun tj]# ((m>15&&n>25)) && echo 1 || echo 0
1
[root@aliyun tj]# ((m>15||n>25)) && echo 1 || echo 0  
1
[root@aliyun tj]# ((m>25||n>25)) && echo 1 || echo 0 
1
[root@aliyun tj]# ((m>25||n>35)) && echo 1 || echo 0 
0
[root@aliyun tj]# ((m>25 -a n>35)) && echo 1 || echo 0  
-bash: ((: m>25 -a n>35: syntax error in expression (error token is "n>35")
0


示例总结:

  • “-a”和“-o”逻辑操作符号需要用于[]中

  • “&&”和“||”逻辑操作符号可用于[[]]或(())中,也可以在外部连接多个[]

  •  注意,在[]和[[]]的两端及比较符号的两端,必须要有空格,但是对于(())不需要




六:测试表达式test、[]、[[]]、(())的区别总结


如下表所示:


测试表达式操作符


           []


        test


          [[]]

    

          (())


边界是否需要空格


        需要


        需要


         需要


       不需要


逻辑操作符


   !、-a、-o


    !、-a、-o


    !、&&、||


    !、&&、||

整数比较操作符

-eq、-gt、-lt、-ge、-le

-eq、-gt、-lt、-ge、-le

-eq、-gt、-lt、-ge、-le或=、>、<、>=、<=

=、>、<、>=、<=


字符串比较操作符


   =、==、!=


   =、==、!=


  =、==、!=


  =、==、!=


是否支持通配匹配符


      不支持


      不支持


      支持


      不支持


猜你喜欢

转载自blog.51cto.com/13707680/2122595