shell条件测试
一般使用shell处理的条件测试类型有三种:
文件测试
数值比较
字符串比较
文件运算比较符 | 表达式 | 含义 |
-e | -e filename | 如果 filename 存在,则为真 |
-d | -e filename | 如果 filename 为目录,则为真 |
-f | -e filename | 如果 filename 为常规文件 |
-L | -e filename | 如果 filename 为符号链接,则为真 |
-r | -e filename | 如果 filename 可读,则为真 |
-w | -e filename | 如果 filename 可写,则为真 |
-x | -e filename | 如果 filename 可执行,则为真 |
-ot | filename1 -ot filename2 | 如果 filename1 比 filename2 旧,则为真 |
-nt | filename1 -nt filename2 | 如果 filename1 比 filename2 新,则为真 |
字符串运算比较符 | 表达式 | 含义 |
-z | -z string | 如果 string 长度为零,则为真 |
-n | -n string | 如果 string 长度非零,则为真 |
= | string1 = string2 | 如果 string1 与 string2 相同,则为真 |
!= | string1 != string2 | 如果 string1 与 string2 不同,则为真 |
算术比较运算符 | 表达式 | 含义 |
-eq | num1 -eq num2 | 如果num1等于num2,则为真 |
-ne | num1 -ne num2 | 如果num1不等于num2,则为真 |
-lt | num1 -lt num2 | 如果num1小于num2,则为真 |
-le | num1 -le num2 | 如果num1小于等于num2,则为真 |
-gt | num1 -gt num2 | 如果num1大于num2,则为真 |
-ge | num1 -ge num2 | 如果num1大于等于num2,则为真 |
== | num1 == num2 | 如果num1等于num2,则为真 |
!= | num1 != num2 | 如果num1不等于num2,则为真 |
>= | num1 >= num2 | 如果num1大于等于num2,则为真 |
<= | num1 <= num2 | 如果num1小于等于num2,则为真 |
> | num1 > num2 | 如果num1大于num2,则为真 |
< | num1 < num2 | 如果num1小于num2,则为真 |
处理条件测试的方式有以下几种
用法 | 适用范围 | 是否支持正则 | 备注 | |
test | test 条件表达式 | 文件测试、数值比较、字符串比较 | 否 | |
[ ] | [ 条件表达式 ] | 文件测试、数值比较、字符串比较 | 否 | 注意空格 |
[[ ]] | [[ 条件表达式 ]] | 文件测试、数值比较、字符串比较 | 是 | |
(( )) | (( 表达式 )) | 数值比较 | 否 | 注意千万不要用于字符串比较;当表达式单为数字时,0返假,其他全部为真 |
几种处理方式异同,及需要注意的点具体如下:
一、test
test和[ ] 几乎等价可以文件测试、数值比较、字符串比较。不过在进行数字比较时可以用的运算字符只有"-eq",“-ne”,“-lt”,“-le”,“-gt”,“-ge”,“==”,“!=”。
他的优点是:三种条件测试都能可以做,而且是内部命令(所以脚本中可不要定义名为test的变量)。因此,使用范围广,大多数shell都支持。
它的缺点是不支持正则,还有语句不够清晰明了,没有[ ]简洁,易读。
示例:
1、文件测试
# vim test.sh
if test -d /etc then echo "11111111111111" else echo "22222222222222" fi
2、字符串比较测试
if test qaw == aqw then echo "11111111111111" else echo "22222222222222" fi
3、数值比较测试
if test 111 -eq 111 then echo "11111111111111" else echo "22222222222222" fi
4、当后面表达式直接接字符串或者数字时
if test 1111 then echo "11111111111111" else echo "22222222222222" fi
if test qqqq then echo "11111111111111" else echo "22222222222222" fi
直接接字符串时,直接判定为真
5、后面直接接0
if test 0 then echo "11111111111111" else echo "22222222222222" fi
6、后面不接表达式
if test then echo "11111111111111" else echo "22222222222222" fi
不接表达式直接判定为假
二、[ ]
[ ] 和test等价,优缺点几乎相同。但是 [ ] 比test的表达式显然更方便阅读。不过在使用 [ ]千万不要吝啬空格。
可以看下缺少空格的几种情况
1、中括号两边不加空格
vari1=0 vari2=1 if [${vari1} == ${vari2}] then echo "11111111111111" else echo "22222222222222" fi
可以看到会报语法错误,并且脚本还会执行下去,并且会默认判断为假
2、运算符两侧不加空格
vari1=0 vari2=1 if [ ${vari1}==${vari2} ] then echo "11111111111111" else echo "22222222222222" fi
不会报错,并且会默认为真(应该是当字符串处理了)。这点需要注意,会导致脚本达不到预期处理效果。
其他一些特殊情况,如表达式为空,表达式为0等情况和test完全一样
3、如果误使用了 ">" , "<",”>=“,"<="这些算术运算符。
[ ] 会把 ”>“ 和 ”<“当重定向识别了.........
当使用”>“和”<“时
vari1=0 vari2=1 if [ ${vari1} > ${vari2} ] then echo "11111111111111" else echo "22222222222222" fi
脚本执行并没有报错。但是输出的结果错误,看下具体执行过程
可以看到他判断的对象只有${vari1}即”0“,所以返回结果为真。
不过这种情况可以使用 '' 或者 ”“ 或者 转义符 \ 来避免。不过确实时太麻烦了,而且容易出错
当误使用">="和”<=“时。
vari1=0 vari2=1 if [ ${vari1} >= ${vari2} ] then echo "11111111111111" else echo "22222222222222" fi
脚本执行会直接报错。
这种情况使用引号或者转义符也不能避免
所以当使用[ ] 时。数值的判断最好好养成习惯使用 "-eq",“-ne”,“-lt”,“-le”,“-gt”,“-ge”。不然当碰到那些不报错的情况时,排错都不好排。
三、[[ ]]
[[ ]]其实相当于[ ]的扩展,支持字符串的模式匹配,使用=~操作符时甚至支持shell的正则表达式!逻辑组合可以不使用test的-a,-o而使用&&,||这样更亲切的形式(针对c、Java程序员)。也可以使用运算符 >、<。
但是同样的,它的使用也要十分注意空格。
基本使用和 [ ] 一样,依然说一些比较特殊,或者不同的情况。
1、也可以使用运算符 >、<
vari1=0 vari2=1 if [[ ${vari1} > ${vari2} ]] then echo "11111111111111" else echo "22222222222222" fi
但是对于二元运算符”>=“和”<=“仍不可使用,并且会直接报错
vari1=0 vari2=1 if [[ ${vari1} >= ${vari2} ]] then echo "11111111111111" else echo "22222222222222" fi
2、可以使用逻辑运算符 &&,||,!
但是这里有个大坑
if [[ a != b && 5 > 3 ]] then echo "11111111111111" else echo "22222222222222" fi
数字比较,结果正确。但有时候
if [[ a != b && 15 > 3 ]] then echo "11111111111111" else echo "22222222222222" fi
???????????????????
结果就会很奇怪
其实不光在[[ ]]中,在 [ ] 使用也是如此
所以在shell脚本中,数值的判断最好好养成习惯使用 "-eq",“-ne”,“-lt”,“-le”,“-gt”,“-ge”。
另外,其实如果两个数是相同位数时,结果不会错。
”>“的判定逻辑有点奇怪,比较像sort。只会判断第一位数的大小。而不会管这个数是几位数。所以尽量还是不要用,毕竟在脚本中大多是变量比较,而我们无法确定要比较的两个变量位数是否相同。
3、支持通配符扩展
if [[ hello = hell? ]] then echo "11111111111111" else echo "22222222222222" fi
4、当表达式为空。会直接报错
5、当表达式为0,或者其他时。默认为真,并且可以看到默认为 [[ -n ]]
if [[ 0 ]] then echo "11111111111111" else echo "22222222222222" fi
四、(( ))
(( ))只适用于数值比较,里面语法比较接近C,JAVA编程成语言。可以不加空格(也可以加),变量可以不加$或${}(也可以加)。支持算术运算符,赋值运算符,逻辑运算符,位运算符,条件运算符。
1、不加$,${} 和空格
vari1=55 vari2=200 if ((vari1>vari2)) then echo "11111111111111" else echo "22222222222222" fi
加上${}和空格
vari1=55 vari2=200 if (( ${vari1} > ${vari2} )) then echo "11111111111111" else echo "22222222222222" fi
可以看到结果并无差别
2、赋值运算。=
[[ ]]和[ ] 中"="和”==”好像并无差别,但是(( )) 中“=”属于赋值运算符,“=="才是关系运算符
vari1=55 vari2=200 if ((vari1=vari2)) then echo $vari1 echo "11111111111111" else echo "22222222222222"
vari1=55 vari2=200 if ((vari1==vari2)) then echo $vari1 echo "11111111111111" else echo "22222222222222"
而且对于赋值运算符"=" 两边不能有空格。而关系运算符 ”==“可以有,也可以没有空格
3、赋值运算
(( ))其实也可以单独拿出来做数字的计算
4、逻辑运算符
vari1=200 vari2=200 vari3=200 vari4=200 if (( ${vari1} == ${vari2} && ${vari3} == ${vari4} )) then echo echo "11111111111111" else echo "22222222222222" fi
支持逻辑短路
vari1=200 vari2=200 vari3=200 vari4=201 if (( ${vari1} == ${vari2} == ${vari3} == ${vari4} )) then echo "11111111111111" else echo "22222222222222" fi
这一点在比较多个数的时候非常方便。
如果是用[[ ]]的话只能写为 [[ ${vari1} == ${vari2} && ${vari2} == ${vari3} && ${vari3} == ${vari4} ]]或者[[ {vari1} == ${vari2} ]] && [[ ${vari2} == ${vari3} ]] && [[ ${vari3}== ${vari4} ]]
而用[ ] 的话只能写为 [ ${vari1} == ${vari2} ] && [ ${vari2} == ${vari3} ] && [ ${vari3} == ${vari4} ]
5、表达式为空时,不报错,默认判定为假
vari1=200 vari2=200 vari3=200 vari4=201 if (()) then echo "11111111111111" else echo "22222222222222" fi
6、表达式为0时
if ((0)) then echo "11111111111111" else echo "22222222222222" fi
这里和[[ ]] 以及[ ] 不同。(( ))语法和C语言差不多,所以为0时,会直接判定为假。
而其他数字(包括负数) ,都会判定为真
7、表达式误写为字母时,默认判定为假
if ((edkio)) then echo "11111111111111" else
这里应该也是和C语言语法有关,在C语言中,没有定义的变量值默认为0。由于双括号中变量也可以不加$或者${},所以edkio默认认为时变量