Difference between single and double square brackets in Bash

I'm reading bash examples about if but some examples are written with single square brackets:

if [ -f $param ]
then
  #...
fi

others with double square brackets:

if [[ $? -ne 0 ]]
then
    start looking for errors in yourlog
fi

What is the difference?


Single [] are posix shell compliant condition tests.

Double [[]] are an extension to the standard [] and are supported by bash and other shells (eg zsh, ksh). They support extra operations (as well as the standard posix operations). For example: || instead of -o and regex matching with =~ . A fuller list of differences can be found in the bash manual section on conditional constructs.

Use [] whenever you want your script to be portable across shells. Use [[]] if you want conditional expressions not supported by [] and don't need to be portable.


Behavior differences

Tested in Bash 4.3.11:

  • POSIX vs Bash extension:

  • [ is POSIX
  • [[ is a Bash extension
  • regular command vs magic

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

    ] is just an argument of [ that prevents further arguments from being used.

    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

  • <

  • [[ a < b ]] : lexicographical comparison
  • [ a < b ] : Same as above. required or else does redirection like for any other command. Bash extension.
  • I could not find a POSIX alternative to this, see: How to test strings for less than or equal?
  • && and ||

  • [[ a = a && b = b ]] : true, logical and
  • [ a = a && b = b ] : syntax error, && parsed as an AND command separator cmd1 && cmd2
  • [ a = a -ab = b ] : equivalent, but deprecated by POSIX
  • [ a = a ] && [ b = b ] : POSIX recommendation
  • (

  • [[ (a = a || a = b) && a = b ]] : false
  • [ ( a = a ) ] : syntax error, () is interpreted as a subshell
  • [ ( a = a -oa = b ) -aa = b ] : equivalent, but () is deprecated by POSIX
  • ([ a = a ] || [ a = b ]) && [ a = b ] POSIX recommendation
  • word splitting

  • x='a b'; [[ $x = 'ab' ]] x='a b'; [[ $x = 'ab' ]] : true, quotes not needed
  • x='a b'; [ $x = 'ab' ] x='a b'; [ $x = 'ab' ] : syntax error, expands to [ ab = 'ab' ]
  • x='a b'; [ "$x" = 'ab' ] x='a b'; [ "$x" = 'ab' ] : equivalent
  • =

  • [[ ab = a? ]] [[ ab = a? ]] : true, because it does pattern matching ( * ? [ are magic). Does not glob expand to files in current directory.
  • [ ab = a? ] [ ab = a? ] : a? glob expands. So may be true or false depending on the files in the current directory.
  • [ ab = a? ] [ ab = a? ] : false, not glob expansion
  • = and == are the same in both [ and [[ , but == is a Bash extension.
  • printf 'ab' | grep -Eq 'a.' : POSIX ERE equivalent
  • [[ ab =~ 'ab?' ]] [[ ab =~ 'ab?' ]] : false, loses magic with ''
  • [[ ab? =~ 'ab?' ]] [[ ab? =~ 'ab?' ]] : true
  • =~

  • [[ ab =~ ab? ]] [[ ab =~ ab? ]] : true, POSIX extended regular expression match, ? does not glob expand
  • [ a =~ a ] : syntax error
  • printf 'ab' | grep -Eq 'ab?' : POSIX equivalent
  • Recommendation

    I prefer to always use [] .

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

    If you use [[ ]] you:

  • lose portability
  • force the reader to learn the intricacies of another bash extension. [ is just a regular command with a weird name, no special semantics are involved.

  • Inside single brackets for condition test (ie [ ... ]), some operators such as single = is supported by all shells, whereas use of operator == is not supported by some of the older shells.

    Inside double brackets for condition test (ie [[ ... ]]), there is no difference between using = or == in old or new shells.

    Edit: I should also note that: In bash, always use double brackets [[ ... ]] if possible, because it is safer than single brackets. I'll illustrate why with the following example:

    if [ $var == "hello" ]; then
    

    if $var happens to be null / empty, then this is what the script sees:

    if [ == "hello" ]; then
    

    which will break your script. The solution is to either use double brackets, or always remember to put quotes around your variables ( "$var" ). Double brackets is better defensive coding practice.

    链接地址: http://www.djcxy.com/p/17474.html

    上一篇: 双方括号在bash中的含义

    下一篇: Bash中单方括号和双方括号的区别