文章目录
- 1. []和test
- 2. []和[[]]区别
- 2.1 先有[] 语法,并内置于linux系统,后来才有 [[]]
- 2.2 [] 语法 都可以由 [[]] 替代,并且后者功能更丰富。
- 2.3 二者都建议在表达式和括号自身使用空格避免出错
- 2.4 [] 和 [[]] 中,字符串可以不加引号,此时等号右侧支持通配符
- 2.5 当目标是数字类型时,二者都可以使用 -eq进行数字比较
- 2.6 当目标是数字类型时,都支持>、>=等 数字比较符
- 2.7 都可以使用= 、!=进行字符串比较
- 2.8 在逻辑表达式语法稍有不同,[] 使用 -a、-o 分别表示与、或 关系 ,[[]]使用 &&、 ||表示与 、或关系
- 2.9 逻辑运算符的优先级
- 2.10 [[]]支持字符串模糊匹配,而[]不支持
- 2.11 [[]]支持=~字符串模糊匹配,而[]不支持
- 总结
- 参考
相关文章:
【Linux】shell中的逻辑运算符 和 布尔运算符 && ||
Shell test 命令
总结shell 中各种括号的用法 () (())、[]、[[]]、{})
1. []和test
Shell中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试
test常用于 if ,作为判断条件,if test等价于 if [ ]
,因此,test和[] 内的内容完全可以直接互换!都支持
[]用作判断表达式语法时,和test 语法一致,可以参见 Shell test 命令
[]与其他括号的语法对比,可以参见 总结shell 中各种括号的用法 () (())、[]、[[]]、{}) 中的示例
当然test也可以单独执行,如果当前目录存在hello.sh文件,则会获得返回值 0:
[root@linuxforliuhj test]# test -f hello.sh
[root@linuxforliuhj test]# echo $?
0
上面命令等价于下面语法:
[root@linuxforliuhj test]# [ -f hello.sh ]
[root@linuxforliuhj test]# echo $?
0
因此 [] 就是一个内置命令,有返回值,而不是一个符号,其返回值可以被if 使用作为条件
执行结果0 表示 true ,1 表示false
2. []和[[]]区别
[] 或 [[]] 中,$a 表示变量a,如果没有$符号,默认为字符串,即 [[ a = b ]]等价于 [[ ‘a’ = ‘b’ ]]
为了便于举例,我们在使用[] 或[[]] 语法进行字符串判断时,通常把带有变量的 置于左侧,右侧是静态字符串或带有模糊匹配符号的字符串表达式,甚至有的语法变量只能在左侧!
2.1 先有[] 语法,并内置于linux系统,后来才有 [[]]
起初不是所有的都支持 [[]] ,当然后来基本上都支持了
2.2 [] 语法 都可以由 [[]] 替代,并且后者功能更丰富。
二者大部分语法都相同,但是默认情况下 [] 识别的运算符比较少
,需要使用转义字符等,下面会详解列出不同之处。
2.3 二者都建议在表达式和括号自身使用空格避免出错
例如 if [[ $1 != "start" && $1 != "stop" ]]
,加空格一定不会报错,不加可能会报错
如果写成下面这样,则会报错 if [[ $1 != "start" && $1 !="stop" ]]
,stop和前面的符号没有空格!
2.4 [] 和 [[]] 中,字符串可以不加引号,此时等号右侧支持通配符
先举个例子 [[ $a == ab ]] 判断a的变量值是否等于 ‘ab’,等价于 [[ $a == ‘ab’ ]]
使用单括号也是可以的 [ $a == ab ] 不会报错
注意:此时[]语法下,左侧字符串变量不能含有空格,[[]]
下文会详解用法和注意事项
2.5 当目标是数字类型时,二者都可以使用 -eq进行数字比较
相比于>等数学符号,当使用-eq,并且类型被错误的赋值为非数字时,会提示错误,这样便于检查语法错误,因此建议使用 -eq 替代传统的数学符号。
示例:
a=10
b=20
if [ $a -eq $b ]
then
echo "$a -eq $b : a 等于 b"
else
echo "$a -eq $b: a 不等于 b"
fi
2.6 当目标是数字类型时,都支持>、>=等 数字比较符
但是都 不建议使用,建议使用 -eq语法
但是要注意的是 [] 需要增加转义字符
,原因是[]默认 不识别特殊字符,而[[]] 天生支持
a=10;b=20; [ $a < $b ] ;echo $? //单中括号执行报错,不识别 <号
a=10;b=20; [[ $a < $b ]];echo $? //双中括号执行成功 ,打印0
a=10;b=20; [ $a \< $b ] ;echo $? //转义字符执行成功,打印0
a=10;b=20aabc; [[ $a < $b ]];echo $? //不会报错,当目标误传为字符串时,不容易发现错误,因此不建议使用 <这种语法,建议使用 -eq语法
2.7 都可以使用= 、!=进行字符串比较
需要注意的是,当字符串类型且有空格时,[]需要对字符串加引号,而[[]] 可加可不加
#可以在终端命令行直接输入命令,分号是多条命令的分割符
x='a b'; [ $x = 'a b' ] //单中括号,当字符串变量的值含有空格时,需要小心,执行会报错 [: too many arguments 错误,原因是把空格当做分割符了
x='a b'; [ "$x" = 'a b' ] //单中括号,添加引号后,执行成功
x='a b'; [[ $x = 'a b' ]] //双中括号,天生就可以执行成功
当字符串类型且含有特殊字符,例如`*号`时,[]会报错,而[[]] 不会
x='*'; [ $x = 'a b' ] // bash: [: too many arguments
x='*'; [[ $x = 'a b' ]] // 执行成功
2.8 在逻辑表达式语法稍有不同,[] 使用 -a、-o 分别表示与、或 关系 ,[[]]使用 &&、 ||表示与 、或关系
中括号 ”与逻辑 “ 示例:
if [ $a -lt 100 -a $b -gt 15 ]
then
echo "$a 小于 100 且 $b 大于 15 : 返回 true"
else
echo "$a 小于 100 且 $b 大于 15 : 返回 false"
fi
双中括号 “与逻辑” 示例:
[[ a = a && b = b ]]
单中括号不支持 &&语法,即使添加转义字符也不行,可以再外层使用 && :
[ a = a && b = b ] //错误
[ a = a ] && [ b = b ] //可以改造成这样,外部通过 &`在这里插入代码片`& 进行连接
2.9 逻辑运算符的优先级
优先级顺序 按照 : ()逻辑 > && > || ,并且单[] 不识别 小括号(),除非加转义字符
unset a;unset b; //清除a b 变量,防止影响执行结果
[[ (a = a || a = b) && a = b ]];echo $? //注意是双中括号,最终结果为1 ,false ,先计算(a = a || a = b) 得到结果true ,然后再计算 true && a = b
[[ a = a || a = b && a = b ]];echo $? // 注意是双中括号,最终结果为0 ,true,先计算右边 a = b && a = b,得到false,然后计算 a=a || false
[ ( a = a ) ] //报错,bash: syntax error near unexpected token 'a',即单括号不识别括号
[ \( a = a -o a = b \) -a a = b ] //没有语法错误
2.10 [[]]支持字符串模糊匹配,而[]不支持
注意:
-
右侧不加引号时,支持通配符,左边是字符串,顺序不能颠倒
;要想屏蔽通配符,需要加 转义字符; -
如果右侧是带引号的,此时就是普通字符串
-
* 可以使用星号代替零个、单个或多个字符;
-
? 问号代替一个字符,必须有一个
当是=号时,通配符表示是否以满足xxx条件
[[ ab = a? ]]; echo $? //打印 0 true,因为 ?被当做通配符
[[ a? = ab ]]; echo $? //打印 1 false,颠倒了通配符因为失效了,在左侧就是普通字符串,等价于 [[ 'a?' = 'ab' ]]; echo $?
[[ ab = a\? ]]; echo $? //打印 1 false,因为加了转义字符,右侧通配符就是字符串了
[[ ab =~ 'ab?' ]]; echo $? //打印 1 false ,因为加了引号,就是普通字符串
当然通配符也可以用在前面:
[[ ab = ?b ]];echo $? //打印 0 true
并且特别要注意的是,[] 中右侧的?匹配符号会被当做当前目录下的文件名称进行匹配,而不是字符串匹配了;
右侧*匹配符直接报错!前文得知,在左侧当做普通字符串,也报错,因此 禁用 *
因此建议禁用 通配符
rm -f ab;touch ab;[ ab = a? ]; echo $? # 打印 0 true ,此时语法等价于 “是否当前目录存在ab这个文件,并且以a开头 ?” 比较别扭,也就是说 ab不再是字符串,而是当前目录的文件名称
rm -f ab;[ ab = a? ]; echo $? # 打印 1 false
rm -f ab;touch ab;[ ab = a* ]; echo $? # *号匹配符直接报错,
2.11 [[]]支持=~字符串模糊匹配,而[]不支持
严格来说,这里的模糊匹配是指正则表达式:
[[ "string" =~ pattern ]]
示例:
$ [[ efabm =~ ab ]];echo $? //最简单的匹配,等价于 [[ efabm = *ab* ]]
0
$ [[ '234' =~ \d ]];echo $? // 虽然是全数字,但是不支持\d,把后面当做普通字符
1
$ [[ '234' =~ ^[0-9]+$ ]];echo $? //全数字?对
0
$ [[ 234a =~ ^[0-9]+$ ]];echo $? //全数字?错
1
注意与!=进行区别,!=是不等于,而=~是正则语法。
而[] 压根不支持=~,直接报错:
[ a =~ a ] # 报错 bash: [: =~: binary operator expected
总结
尽量不用[],建议使用 [[]]
参考
linux shell if的[]和[[]]
[What is the difference between the Bash operators [[ vs vs ( vs ((?