• shell脚本的条件判断3:探究[[]]和[]的区别


    前言

    实例中除非特别标注,否则都不是在centos中测试的。

    一 简述 

    多数情况下[]和[[]]是可以通用的,两者的主要差异是:test或[]是符合POSIX标准的测试语句,兼容性更强,几乎可以运行在所有Shell解释器中,相比较而言[[]]仅可运行在特定的几个Shell解释器中(如Bash、Zsh等)。事实上,目前支持使用[[]]进行条件测试的解释器已经足够多了。使用[[]]进行测试判断时甚至可以使用正则表达式。

    二 实例对比  

    首先,测试两者的通用表达式(同样,一定要注意空格的问题,空格不可或缺)。 

    相同点

    1. csdn@ubuntu:~$ [[ 5 -eq 5 ]] && echo Y || echo N
    2. Y
    3. csdn@ubuntu:~$ [[ -r main.c ]] && echo Y || echo N
    4. N
    5. csdn@ubuntu:~$ [[ -r other.c ]] && echo Y || echo N
    6. Y
    7. csdn@ubuntu:~$ [ 5 -eq 5 ] && echo Y || echo N
    8. Y
    9. csdn@ubuntu:~$ [ -r main.c ] && echo Y || echo N
    10. N
    11. csdn@ubuntu:~$ [ -r other.c ] && echo Y || echo N
    12. Y
    13. csdn@ubuntu:~$

    排序的区别 

    看两者的差异点。其中,在[[]]中使用<和>符号时,系统进行的是排序操作,而且支持在测试表达式内使用&&和||符号。在test或[]测试语句中不可以使用&&和||符号。

    注意 

    [[ ]]中的表达式如果使用<或>进行排序比较,使用的是本地的locale语言顺序。可以使用LANG=C设置在排序时使用标准的ASCII码顺序。

    在ASCII码的顺序中,小写字母顺序码>大写字母顺序码>数字顺序码。

    我的系统默认LANG值是zh_CN.UTF-8,所说义[]和[[]]的排序结果是不同的。

    1. csdn@ubuntu:~$ echo $LANG
    2. zh_CN.UTF-8
    3. csdn@ubuntu:~$ [ a > A ] && echo Y || echo N
    4. Y
    5. csdn@ubuntu:~$ [[ a > A ]] && echo Y || echo N
    6. N
    7. csdn@ubuntu:~$

     修改LANG=C

    1. csdn@ubuntu:~$ LANG=C
    2. csdn@ubuntu:~$ [[ a > A ]] && echo Y || echo N
    3. Y
    4. csdn@ubuntu:~$ [ a > A ] && echo Y || echo N
    5. Y
    6. csdn@ubuntu:~$

    条件中的与或区别 

    虽然[]也支持同时进行多个条件的逻辑测试,但是在[]中需要使用-a和-o进行逻辑与和逻辑或的比较操作,而[[]]中可以直接使用&&和||进行逻辑比较操作,更直观,可读性更好。A && B或者A -a B,意思是仅当A和B两个条件测试都成功时,整体测试结果才为真。A || B或者A -o B,意思是只要A或B中的任意一个条件测试成功,则整体测试结果为真。

    1. csdn@ubuntu:~$ [ y == y -a n == n ] && echo Y || echo N
    2. Y
    3. csdn@ubuntu:~$ [ y == n -o n == n ] && echo Y || echo N
    4. Y
    5. csdn@ubuntu:~$ [ y == n -a n == n ] && echo Y || echo N
    6. N
    7. csdn@ubuntu:~$ [ y == n -o n == n ] && echo Y || echo N
    8. Y
    9. csdn@ubuntu:~$ [ y == n -o n == y ] && echo Y || echo N
    10. N
    11. csdn@ubuntu:~$ [[ y == n && n == y ]] && echo Y || echo N
    12. N
    13. csdn@ubuntu:~$ [[ y == y || n == y ]] && echo Y || echo N
    14. Y
    15. csdn@ubuntu:~$ [[ y == y || n == y ]] && echo Y || echo N
    16. Y
    17. csdn@ubuntu:~$ [[ y == n || n == y ]] && echo Y || echo N
    18. N
    19. csdn@ubuntu:~$

     需要注意的还有==比较符,在[[]]中==是模式匹配,模式匹配允许使用通配符。例如,Bash常用的通配符有*、? 、[…]等。而==在test语句中仅代表字符串的精确比较,判断字符串是否一模一样。下面的例子,测试变量name的值是否以字母c开头,后面可以是任意长度的任意字符,测试结果为真。总是使用之前多测试吧,感觉不太靠谱的样子。

    1. csdn@ubuntu:~$ name=csdn
    2. csdn@ubuntu:~$ [[ $name == c* ]] && echo Y || echo N
    3. Y
    4. csdn@ubuntu:~$ [[ $name == c... ]] && echo Y || echo N
    5. N
    6. csdn@ubuntu:~$ [[ $name == c* ]] && echo Y || echo N
    7. Y
    8. csdn@ubuntu:~$ [[ $name == c[a-z]* ]] && echo Y || echo N
    9. Y
    10. csdn@ubuntu:~$ [[ $name == c[a-z]{3} ]] && echo Y || echo N
    11. N
    12. csdn@ubuntu:~$ [[ $name == c[.]{3} ]] && echo Y || echo N
    13. N
    14. csdn@ubuntu:~$ [[ $name == c[.]{4} ]] && echo Y || echo N
    15. N
    16. csdn@ubuntu:~$

    接着,测试变量name的值是否以字母d开头,后面可以是任意长度的任意字符,测试结果为假。 

    1. csdn@ubuntu:~$ [[ $name == d* ]] && echo Y || echo N
    2. N
    3. csdn@ubuntu:~$

     测试变量name的值是否是c和dn中间有任意单个字符?结果为真

    1. csdn@ubuntu:~$ [[ $name == c?dn ]] && echo Y || echo N
    2. Y
    3. csdn@ubuntu:~$

    测试字符a,是否是小写字母?结果为真。

    1. csdn@ubuntu:~$ [[ a == [a-z] ]] && echo Y || echo N
    2. Y
    3. csdn@ubuntu:~$

     同样是使用==进行比较操作,但在[]中系统进行的是字符串的比较操作,判断两个字符串是否绝对相同。

    下面是在ubuntu中测试的,会报错的。 

    1. csdn@ubuntu:~$ [ c == c ] && echo Y || echo N
    2. Y
    3. csdn@ubuntu:~$ [ c == c* ] && echo Y || echo N
    4. bash: [: too many arguments
    5. N
    6. csdn@ubuntu:~$

     下面的是在centOS7中测试的,不会报错:

    1. [lkmao@MiWiFi-R3600-srv root]$ [ c == c* ] && echo Y || echo N
    2. N
    3. [lkmao@MiWiFi-R3600-srv root]$ name=csdn
    4. [lkmao@MiWiFi-R3600-srv root]$ [ $name == c* ] && echo Y || echo N
    5. N
    6. [lkmao@MiWiFi-R3600-srv root]$

    另外,在[[]]中还支持使用=~进行正则匹配,而在[]中则完全不支持正则匹配。对变量name的值进行正则匹配,判断name的值是否包含字母c。

    1. csdn@ubuntu:~$ [[ $name =~ c ]] && echo Y || echo N
    2. Y
    3. csdn@ubuntu:~$

     对变量name的值进行正则匹配,判断name的值是否包含数字。

    1. csdn@ubuntu:~$ [[ $name =~ [0-9] ]] && echo Y || echo N
    2. N
    3. csdn@ubuntu:~$

     对变量name的值进行正则匹配,判断name的值是否包含小写和大写字母。

    1. csdn@ubuntu:~$ [[ $name =~ [a-z] ]] && echo Y || echo N
    2. Y
    3. csdn@ubuntu:~$ name=Csdn
    4. csdn@ubuntu:~$ [[ $name =~ [a-z] ]] && echo Y || echo N
    5. Y
    6. csdn@ubuntu:~$ [[ $name =~ [A-Z] ]] && echo Y || echo N
    7. Y
    8. csdn@ubuntu:~$

     最后,看看分组测试。使用()进行分组,效果类似于虽然在数学上默认先算乘除法再算加减法,但使用()后可以先算加减法再算乘除法。

    下面这条命令,在a==a为真的情况下,b==b和c==d两个测试中只要有一个测试为真,则整体测试为真。多测几个值总是好的。测试原理中分条件测试、分支测试、路径测试。总之要测全,搞不好,你正在用的shell就不兼容某种用法。

    1. csdn@ubuntu:~$ [[ a == a ]] && echo Y || echo n
    2. Y
    3. csdn@ubuntu:~$ [[ a == a ]] && echo Y || echo N
    4. Y
    5. csdn@ubuntu:~$ [[ a == a && (b == b) ]] && echo Y || echo N
    6. Y
    7. csdn@ubuntu:~$ [[ a == a && ((b == b) && (c == c)) ]] && echo Y || echo N
    8. Y
    9. csdn@ubuntu:~$ [[ a == a && ((b == b) && (c == d)) ]] && echo Y || echo N
    10. N
    11. csdn@ubuntu:~$ [[ a == a && ((b == b) || (c == d)) ]] && echo Y || echo N
    12. Y
    13. csdn@ubuntu:~$

     终于学到尾声了。快吐了。

    列出了[[]]和[]的差异汇总信息,相同点这里不再赘述。为了熟练掌握这些语法,本书后面的案例中将混合应用多种不同的条件测试语句。

    小结 

  • 相关阅读:
    PostgreSQL serial类型
    Dom.nodeType
    Springboot整合Seata
    Unity脚本常用API Day03
    map的一些测试-string键的查找
    go context 源码刨析(一)
    一文带你快速搭建框架(最全MyBatis笔记)
    lock和synchronized的区别
    @GrpcServise 注解的作用和使用
    PyTorch - autograd自动微分
  • 原文地址:https://blog.csdn.net/yueni_zhao/article/details/128053377