• bash中 [ ] 与 [[ ]] 的区别


      参考:http://www.zsythink.net/archives/2252

      如果直接描述 [ ] 与 [[ ]] 的区别,反而不太容易理解,不如先来看一些应用场景,根据应用场景,反而更容易理解。

      场景一:判断变量是否为空

      我们可以直接判断变量是否为空,方法如下

    [root@node1 ~]# a=abc
    [root@node1 ~]# echo $a
    abc
    [root@node1 ~]# [ $a ]
    [root@node1 ~]# echo $?
    0
    [root@node1 ~]# [[ $a ]]
    [root@node1 ~]# echo $?
    0
    [root@node1 ~]# b=""
    [root@node1 ~]# [ $b ]
    [root@node1 ~]# echo $?
    1
    [root@node1 ~]# [[ $b ]]
    [root@node1 ~]# echo $?
    1
    [root@node1 ~]# 
    

       如上图所示,变量值非空时返回真(即返回值为0),使用上述方法判断变量值是否为空时,[ ] 与 [[ ]] 没有区别,上例中,变量值非空,返回真,我们可以使用"!"进行取反,使得变量值为空时,返回真,示例如下

    [root@node1 ~]# echo $c
    
    [root@node1 ~]# [ ! $c ]
    [root@node1 ~]# echo $?
    0
    [root@node1 ~]# [[ ! $c ]]
    [root@node1 ~]# echo $?
    0
    [root@node1 ~]# ! [ $c ]
    [root@node1 ~]# echo $?
    0
    [root@node1 ~]# ! [[ $c ]]
    [root@node1 ~]# echo $?
    0
    [root@node1 ~]# 
    

       如上图所示,变量c是一个没有被声明赋值的变量,其值为空,我们可以使用上述语法,判断变量c的值是否为空,变量值为空,返回真,同理,上述示例中,[ ] 与 [[ ]] 没有区别。

       那么在判断变量是否为空时,[ ] 与 [[ ]] 的区别在哪里呢?不要着急,我们慢慢聊。

       我们知道,在Linux中,我们可以使用test命令判断一个字符串是否为空,test命令为我们提供了"-z选项"与"-n选项",使用这两个选项可以判断字符串是否为空。

      "-z选项"可以判断指定的字符串是否为空,为空则返回真,非空则返回假,-z可以理解为zero

      "-n选项"可以判断指定的字符串是否为空,非空则返回真,为空则返回假,-n可以理解为nozero

      示例如下

    [root@node1 ~]# test -z ""
    [root@node1 ~]# echo $?
    0
    [root@node1 ~]# test -z "abc"
    [root@node1 ~]# echo $?
    1
    [root@node1 ~]# test -n "abc"
    [root@node1 ~]# echo $?
    0
    [root@node1 ~]# test -n ""
    [root@node1 ~]# echo $?
    1
    [root@node1 ~]# 
    

       正如上图所示,我们通过test命令判断了字符串是否为空,那么我们来尝试一下,使用test命令判断变量的值是否为空,示例如下

       上例中,变量b的值为空,按照正常的逻辑来说,使用test -n 命令判断变量b的值是否为空时,应该返回假,因为test命令的-n选项表示指定的字符串非空时,返回真,为空时,返回假,但是上例中,'test -n $b' 这条命令的返回值却为真(应该为假),这是明显不正确的,所以,为了防止上述情况的发生,在使用test命令的-n选项判断变量的值是否为空时,需要在变量的外侧加上"双引号",示例如下

       好了,我们已经明白了使用test命令判断变量是否为空时的一些注意点,那么话说回来,这篇文章的主题是介绍[ ]与[[ ]]的区别的,为什么我们要先介绍test命令呢?其实,在Linux中,"[ ]"与"test命令"是等效的,比如,我们也可以使用"-n"或者"-z"结合"[ ]"去判断变量是否为空

       根据上例中的结果可以看出,当"[ ]"中使用"-n"或者"-z"这些选项判断变量是否为空时,必须在变量的外侧加上双引号,才更加保险,与"test命令"的使用方法相同。

      不过,使用"[[ ]]"时则不用考虑这样的问题,示例如下

    [root@node1 ~]# a=abc 
    [root@node1 ~]# echo $a
    abc
    [root@node1 ~]# [[ -n $a ]]
    [root@node1 ~]# echo $?
    0
    [root@node1 ~]# [[ -n $b ]]
    [root@node1 ~]# echo $?
    1
    [root@node1 ~]# [[ -z $b ]]
    [root@node1 ~]# echo $?
    0
    [root@node1 ~]# [[ -z $a ]]
    [root@node1 ~]# echo $?
    1
    [root@node1 ~]# 
    

       综上所述,我们可以得出如下结论:

      当使用"-n"或者"-z"这种方式判断变量是否为空时,"[ ]"与"[[  ]]"是有区别的。

      使用"[ ]"时需要在变量的外侧加上双引号,与test命令的用法完全相同,使用"[[  ]]"时则不用。

      场景二:组合判断条件

      在使用shell脚本时,判断几乎是必不可少的,而很多时候,如果想要得到最终的判断结果,可能需要同时对多个条件进行判断,比如,条件一与条件二必须同时为真,结果才为真,再比如,条件一或条件二只要有一个为真,结果即为真。没错,这时,多个条件之间存在"与"或者"或"的关系。

       在shell中,我们可以使用"-a"或者"-o"对多个条件进行连接,然后进行"与运算"或者"或运算",也可以使用"&&"或者"||"对多个条件进行连接,但是,这两种方法对于"[ ]"或者"[[  ]]"来说,是存在区别的,我们通过一些小例子来了解一下这些区别。

       简单示例如下

    [root@node1 ~]# [[ 3 -gt 1 && 5 -lt 18 ]]
    [root@node1 ~]# echo $?
    0
    [root@node1 ~]# [[ 5 -gt 2 || 9 -lt 3 ]]
    [root@node1 ~]# echo $?
    0
    [root@node1 ~]# [[ 3 -gt 1 ]] && [[ 5 -lt 18 ]]
    [root@node1 ~]# echo $?
    0
    [root@node1 ~]# [[ 5 -gt 2 ]] || [[ 9 -lt 3 ]]
    [root@node1 ~]# echo $?
    0
    [root@node1 ~]# 
    

       如上图所示,当使用"[[ ]]"对多个条件进行"与运算"或者"或运算"时,可以一次性将多个条件都包含在一个"[[  ]]"中,然后将每个条件用"&&"或者用"||"连接起来,或者每个条件分别包含在一个"[[  ]]"中,然后再用"&&"或者用"||"连接起来,正如上图所示,这两种写法都是没有问题的。

      那么,使用"[[  ]]"时,能否使用"-a"或者"-o"对多个条件进行连接呢?我们来实验一下,示例如下

    [root@node1 ~]# [[ 3 -gt 1 -a 5 -lt 18 ]]
    -bash: 条件表达式中有语法错误
    -bash: `-a' 附近有语法错误
    [root@node1 ~]# [[ 3 -gt 1 ]] -a [[ 5 -lt 18 ]]
    -bash: 未预期的符号 `-a' 附近有语法错误
    [root@node1 ~]# [[ 5 -gt 2 -o 9 -lt 3 ]]
    -bash: 条件表达式中有语法错误
    -bash: `-o' 附近有语法错误
    [root@node1 ~]# [[ 5 -gt 2 ]] -o [[ 9 -lt 3 ]]
    -bash: 未预期的符号 `-o' 附近有语法错误
    [root@node1 ~]# 
    

       看来,使用"[[  ]]"时,是不能使用"-a"或者"-o"对多个条件进行连接的。

       仍然使用上述套路,我们将"[[  ]]"换成"[  ]"试试。

    [root@node1 ~]# [ 3 -gt 1 -a 5 -lt 8 ]
    [root@node1 ~]# echo $?
    0
    [root@node1 ~]# [ 3 -gt 1 ] -a [ 5 -gt 8 ]
    -bash: [: 参数太多
    [root@node1 ~]# [ 5 -gt 2 -o 9 -lt 3 ]
    [root@node1 ~]# echo $?
    0
    [root@node1 ~]# [ 5 -gt 2 ] -o [ 9 -lt 3 ]
    -bash: [: 参数太多
    [root@node1 ~]# 
    

        看来,当使用"[  ]"时,如果使用"-a"或者"-o"对多个条件进行连接,"-a"或者"-o"必须被包含在"[ ]"之内,才能够正常使用,否则会报语法错误。 

      "-a"或者"-o"的使用方法我们已经在"[  ]"中进行了验证,现在,我们来试试"&&"或者"||"在"[  ]"中的使用方法,示例如下

    [root@node1 ~]# [ 3 -gt 1 && 5 -lt 8 ]
    -bash: [: 缺少 `]'
    [root@node1 ~]# [ 3 -gt 1 ] && [ 5 -lt 8 ]
    [root@node1 ~]# echo $?
    0
    [root@node1 ~]# [ 5 -gt 2 || 9 -lt 3 ]
    -bash: [: 缺少 `]'
    -bash: 9: 未找到命令
    [root@node1 ~]# [ 5 -gt 2 ] || [ 9 -lt 3 ]
    [root@node1 ~]# echo $?
    0
    [root@node1 ~]# 
    

       从上例中可以看出,与"-a"或者"-o"的使用方法正好相反,当使用"[  ]"时,如果使用"&&"或者"||"对多个条件进行连接,"&&"或者"||"必须在"[ ]"之外,否则会报语法错误。

      综上所述,我们可以总结出如下结论:

      在使用"[[  ]]"时,不能使用"-a"或者"-o"对多个条件进行连接。

      在使用"[  ]"时,如果使用"-a"或者"-o"对多个条件进行连接,"-a"或者"-o"必须被包含在"[ ]"之内。

      在使用"[  ]"时,如果使用"&&"或者"||"对多个条件进行连接,"&&"或者"||"必须在"[ ]"之外。


      场景三:某些运算符

      如果想要判断变量的值是否满足某个正则表达式,我们可以使用符号"=~"进行判断,示例如下:

    [root@node1 ~]# tel=13688888888
    [root@node1 ~]# [[ $tel =~ [0-9]{11} ]]
    [root@node1 ~]# echo $?
    0
    [root@node1 ~]# tel=1368888888k
    [root@node1 ~]# [[ $tel =~ [0-9]{11} ]]
    [root@node1 ~]# echo $?
    1
    [root@node1 ~]# 
    

       如上图所示,我们通过"=~",可以判断一个变量的值是否匹配对应的正则表达式,但是细心如你一定发现了,上例中使用了"[[  ]]",如果把"[[  ]]"替换成"[  ]",能否同样正常运转呢?我们来试试。

    [root@node1 ~]# tel=13688888888
    [root@node1 ~]# [ $tel =~ [0-9]{11} ]
    -bash: [: =~: 期待二元表达式
    [root@node1 ~]# 
    

       看来是不能这样使用的,所以我们可以得出结论,"=~"只能应用于"[[  ]]"中,不能应用于"[  ]"中。

      小结

      当使用"-n"或者"-z"这种方式判断变量是否为空时,"[ ]"与"[[  ]]"是有区别的。

      使用"[ ]"时需要在变量的外侧加上双引号,与test命令的用法完全相同,使用"[[  ]]"时则不用。

       在使用"[[  ]]"时,不能使用"-a"或者"-o"对多个条件进行连接。

      在使用"[  ]"时,如果使用"-a"或者"-o"对多个条件进行连接,"-a"或者"-o"必须被包含在"[ ]"之内。

      在使用"[  ]"时,如果使用"&&"或者"||"对多个条件进行连接,"&&"或者"||"必须在"[ ]"之外。

       在使用符号"=~"去匹配正则表达式时,只能使用"[[  ]]",当使用">"或者"<"判断字符串的ASCII值大小时,如果结合"[ ]"使用,则必须对">"或者"<"进行转义。

  • 相关阅读:
    FFMPEG音视频基础问题和被面试问到的东西
    OpenGL学习
    FFMPEG起航之旅
    SurfaceView、TextureView对比和学习
    对文件拷贝、删除操作、对时间的计算以及转化
    音视频开发
    企业级Android应用架构设计与开发
    屏幕分辨率的适配&&开发文档的介绍
    设计模式的学习
    自定义Dialog的模版
  • 原文地址:https://www.cnblogs.com/minseo/p/13718343.html
Copyright © 2020-2023  润新知