协慌网

登录 贡献 社区

在 Bash 中,双方括号 [[]] 比单方括号 [] 更可取吗?

最近甲同事权利代码审查该[[ ]]构建体是优选的超过[ ]中样构建体

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

他无法提供理由。有一个吗?

答案

[[具有较少的惊喜,并且通常更安全使用。但是它不是可移植的 - POSIX 没有指定它的功能,只有一些 shell 支持它(除了 bash,我听说 ksh 也支持它)。例如,您可以

[[ -e $b ]]

测试文件是否存在。但是,使用[ ,必须引用$b ,因为它会拆分参数并扩展诸如"a*" (其中[[实际上是接受它的地方)。这还与怎么办[可外接程序,并接受它的参数通常只是像其他程序(虽然它也可以是一个内置的,但后来仍然没有这种特殊处理)。

[[还具有其他一些不错的功能,例如与=~匹配的正则表达式以及类似 C 的语言中已知的运算符。这是一个很好的页面: test, [[[什么区别?和重击测试

Behavior differences

Some differences on Bash 4.3.11:

  • POSIX vs Bash extension:

  • regular command vs magic

    • [ is just a regular command with a weird name.

      ] is just the last argument of [.

      Ubuntu 16.04 actually has an executable for it at /usr/bin/[ provided by coreutils, but the bash built-in version takes precedence.

      Nothing is altered in the way that Bash parses the command.

      In particular, < is redirection, && and || concatenate multiple commands, ( ) generates subshells unless escaped by \, and word expansion happens as usual.

    • [[ X ]] is a single construct that makes X be parsed magically. <, &&, || and () are treated specially, and word splitting rules are different.

      There are also further differences like = and =~.

    In Bashese: [ is a built-in command, and [[ is a keyword: https://askubuntu.com/questions/445749/whats-the-difference-between-shell-builtin-and-shell-keyword

  • <

  • && and ||

    • [[ a = a && b = b ]]: true, logical and
    • [ a = a && b = b ]: syntax error, && parsed as an AND command separator cmd1 && cmd2
    • [ a = a ] && [ b = b ]: POSIX reliable equivalent
    • [ a = a -a b = b ]: almost equivalent, but deprecated by POSIX because it is insane and fails for some values of a or b like ! or ( which would be interpreted as logical operations
  • (

    • [[ (a = a || a = b) && a = b ]]: false. Without ( ), would be true because [[ && ]] has greater precedence than [[ || ]]
    • [ ( a = a ) ]: syntax error, () is interpreted as a subshell
    • [ \( a = a -o a = b \) -a a = b ]: equivalent, but (), -a, and -o are deprecated by POSIX. Without \( \) would be true because -a has greater precedence than -o
    • { [ a = a ] || [ a = b ]; } && [ a = b ] non-deprecated POSIX equivalent. In this particular case however, we could have written just: [ a = a ] || [ a = b ] && [ a = b ] because the || and && shell operators have equal precedence unlike [[ || ]] and [[ && ]] and -o, -a and [
  • word splitting and filename generation upon expansions (split+glob)

    • x='a b'; [[ $x = 'a b' ]]: true, quotes not needed
    • x='a b'; [ $x = 'a b' ]: syntax error, expands to [ a b = 'a b' ]
    • x='*'; [ $x = 'a b' ]: syntax error if there's more than one file in the current directory.
    • x='a b'; [ "$x" = 'a b' ]: POSIX equivalent
  • =

    • [[ ab = a? ]]: true, because it does pattern matching (* ? [ are magic). Does not glob expand to files in current directory.
    • [ ab = a? ]: a? glob expands. So may be true or false depending on the files in the current directory.
    • [ ab = a\? ]: false, not glob expansion
    • = and == are the same in both [ and [[, but == is a Bash extension.
    • case ab in (a?) echo match; esac: POSIX equivalent
    • [[ ab =~ 'ab?' ]]: false, loses magic with '' in Bash 3.2 and above and provided compatibility to bash 3.1 is not enabled (like with BASH_COMPAT=3.1)
    • [[ ab? =~ 'ab?' ]]: true
  • =~

    • [[ ab =~ ab? ]]: true, POSIX extended regular expression match, ? does not glob expand
    • [ a =~ a ]: syntax error. No bash equivalent.
    • printf 'ab\n' | grep -Eq 'ab?': POSIX equivalent (single line data only)
    • awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?': POSIX equivalent.

Recommendation: always use []

There are POSIX equivalents for every [[ ]] construct I've seen.

如果使用[[ ]] ,则:

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

感谢StéphaneChazelas 所做的重要更正和补充。

[[ ]]具有更多功能 - 建议您阅读Advanced Bash 脚本指南,以获取更多信息,尤其是第 7 章中的扩展测试命令部分。测试。

顺便说一句,作为指南, [[ ]]是在 ksh88(1988 年版本的 Korn shell)中引入的。