双方括号[[]]比Bash中的单方括号[]更好吗?

最近在一次代码审查中,一位同事声称[[ ]]结构优于[ ]构造中的[ ] php

if [ "`id -nu`" = "$someuser" ] ; then 
     echo "I love you madly, $someuser"
fi

他没法提供理由。 有吗? html


#1楼

[[]]双括号在某些版本的SunOS下未被移植,而且在函数声明中彻底没有报告:GNU bash,版本2.02.0(1)-release(sparc-sun-solaris2.6) git


#2楼

一个典型的状况,你不能使用[[在autotools configure.ac脚本中,括号有一个特殊和不一样的含义,因此你将不得不使用test而不是[或[[ - 注意测试和[是相同的]程序。 github


#3楼

简而言之,[[更好,由于它不会分叉另外一个进程。 没有括号或单个括号比双括号慢,由于它要求另外一个进程。 正则表达式


#4楼

行为差别 shell

关于Bash 4.3.11的一些区别: ubuntu

  • POSIX vs Bash扩展: bash

  • 常规命令vs魔法 less

    • [只是一个带有奇怪名字的常规命令。 ide

      ]只是[阻止进一步使用参数的论点]

      Ubuntu 16.04实际上在/usr/bin/[由coreutils提供了它的可执行文件,可是bash内置版本优先。

      Bash解析命令的方式没有任何改变。

      特别是, <是重定向, &&|| 链接多个命令, ( )生成子shell,除非由\\转义,而且像往常同样进行单词扩展。

    • [[ X ]]是一个使X被神奇地解析的单一构造。 <&&||()是专门处理的,而且分词规则是不一样的。

      还有其余差别,如==~

      在Bashese: [是一个内置命令, [[是一个关键字: https ://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword

  • <

  • &&||

    • [[ a = a && b = b ]] :true,逻辑
    • [ a = a && b = b ] :语法错误, &&解析为AND命令分隔符cmd1 && cmd2
    • [ a = a -ab = b ] :等效,但由POSIX³弃用
    • [ a = a ] && [ b = b ] :POSIX和可靠的等价物
  • (

    • [[ (a = a || a = b) && a = b ]] :false
    • [ ( a = a ) ] :语法错误, ()被解释为子shell
    • [ \\( a = a -oa = b \\) -aa = b ] :等效,但POSIX不推荐使用()
    • { [ a = a ] || [ a = b ]; } && [ a = b ] { [ a = a ] || [ a = b ]; } && [ a = b ] POSIX等价物⁵
  • 扩展时的单词拆分和文件名生成(split + glob)

    • x='a b'; [[ $x = 'ab' ]] x='a b'; [[ $x = 'ab' ]] :true,不须要引号
    • x='a b'; [ $x = 'ab' ] x='a b'; [ $x = 'ab' ] :语法错误,扩展为[ ab = 'ab' ]
    • x='*'; [ $x = 'ab' ] x='*'; [ $x = 'ab' ] :若是当前目录中有多个文件,则会出现语法错误。
    • x='a b'; [ "$x" = 'ab' ] x='a b'; [ "$x" = 'ab' ] :POSIX等价物
  • =

    • [[ ab = a? ]] [[ ab = a? ]] :是的,由于它确实模式匹配* ? [是魔术]。 不会将glob扩展为当前目录中的文件。
    • [ ab = a? ] [ ab = a? ]a? glob扩展。 所以多是真或假,具体取决于当前目录中的文件。
    • [ ab = a\\? ] [ ab = a\\? ] :false,不是glob扩展
    • ===是在两个相同的[[[==是一个bash扩展。
    • case ab in (a?) echo match; esac case ab in (a?) echo match; esac :POSIX等价物
    • [[ ab =~ 'ab?' ]] [[ ab =~ 'ab?' ]] :false⁴,用''失去魔力
    • [[ ab? =~ 'ab?' ]] [[ ab? =~ 'ab?' ]] :是的
  • =~

    • [[ ab =~ ab? ]] [[ ab =~ ab? ]] :true,POSIX 扩展正则表达式匹配, ? 没有全局扩展
    • [ a =~ a ] :语法错误。 没有bash等价物。
    • printf 'ab\\n' | grep -Eq 'ab?' :POSIX等价物(仅限单行数据)
    • awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?' :POSIX等价物。

建议 :始终使用[]

对于我见过的每一个[[ ]]构造,都有POSIX等价物。

若是您使用[[ ]]您:

  • 失去便携性
  • 强迫读者学习另外一个bash扩展的复杂性。 [只是一个带有奇怪名称的常规命令,不涉及特殊语义。

¹灵感来自Korn shell中的等效[[...]]结构

²可是ab某些值(如+index )失败,而且若是ab看起来像十进制整数则进行数值比较。 expr "x$a" '<' "x$b"适用于二者。

³而且也失败了ab某些值! (

⁴在bash 3.2及以上版本中提供与bash 3.1的兼容性未启用(与BASH_COMPAT=3.1

⁵虽然分组(此处带有{...;}命令组而不是(...)将运行没必要要的子shell)不是必需的|| && shell运算符(而不是||&& [[...]]运算符或-o / -a [运算符]具备相同的优先级。 因此[ a = a ] || [ a = b ] && [ a = b ] [ a = a ] || [ a = b ] && [ a = b ]将是等价的。


#5楼

若是您要关注Google的风格指南

测试,[和[[

[[...]]减小了错误,由于在[[和]]和[[...]]之间没有发生路径名扩展或分词,容许正则表达式匹配,而[...]则没有。

# This ensures the string on the left is made up of characters in the
# alnum character class followed by the string name.
# Note that the RHS should not be quoted here.
# For the gory details, see
# E14 at https://tiswww.case.edu/php/chet/bash/FAQ
if [[ "filename" =~ ^[[:alnum:]]+name ]]; then
  echo "Match"
fi

# This matches the exact pattern "f*" (Does not match in this case)
if [[ "filename" == "f*" ]]; then
  echo "Match"
fi

# This gives a "too many arguments" error as f* is expanded to the
# contents of the current directory
if [ "filename" == f* ]; then
  echo "Match"
fi
相关文章
相关标签/搜索