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. &&
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:
[
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.
上一篇: 双方括号在bash中的含义
下一篇: Bash中单方括号和双方括号的区别