本文参考 Burak Gökmen 的文章 Differences Between Single and Double Brackets in Bash。
test
内置命令:$ type [
[ is a shell builtin
$ [ 3 -eq 3 ] && echo “Numbers are equal”
Numbers are equal
$ test 3 -eq 3 && echo “Numbers are equal”
Numbers are equal
[] 和 test
之间没有任何区别。[ 对于任何 Unix / Linux 系统的 Shell 都可用,因为它是 POSIX 兼容的。
双括号 [[ 是 shell keyword 关键字:
$ type [[
[[ is a shell keyword
[[ 对于绝大多数 Shell 如 Bash、Zsh 等都可用,但是它并非 POSIX 兼容的。
$ [[ 1 < 2 ]] && echo “1 is less than 2”
1 is less than 2
$ [ 1 < 2 ] && echo “1 is less than 2”
bash: 2: No such file or directory
$ [ 1 \< 2 ] && echo “1 is less than 2”
1 is less than 2
这是因为 [] 内将 < 和 > 默认当作是文件重定向符号。
-a
和 -o
:$ [[ 3 -eq 3 && 4 -eq 4 ]] && echo “Numbers are equal”
Numbers are equal
$ [ 3 -eq 3 -a 4 -eq 4 ] && echo “Numbers are equal”
Numbers are equal
$ [[ 3 -eq 3 && (2 -eq 2 && 1 -eq 1) ]] && echo “Parentheses can be used”
Parentheses can be used
$ [ 3 -eq 3 -a (2 -eq 2 -a 1 -eq 1) ] && echo “Parentheses can be used”
bash: syntax error near unexpected token ‘(‘
$ [ 3 -eq 3 -a \( 2 -eq 2 -a 1 -eq 1 \) ] && echo “Parentheses can be used”
Parentheses can be used
并且 [] 内的圆括号前后都需要加空格。
$ name=”Alice”
$ [[ $name = *c* ]] && echo “Name includes c”
Name includes c
$ echo $?
0
$ [ $name = *c* ] && echo “Name includes c”
$ echo $?
1
$ name=”Alice”
$ [[ $name =~ ^Ali ]] && echo ”Regular expressions can be used”
Regular expressions can be used
$ [ $name =~ ^Ali ] && echo ”Regular expressions can be used”
bash: [: =~: binary operator expected
其中,=~
内置运算符表示正则表达式匹配。
$ filename=”nonexistent file”
$ [[ ! -e $filename ]] && echo ”File doesn’t exist”
File doesn’t exist
$ [ ! -e $filename ] && echo ”File doesn’t exist”
bash: [: nonexistent: binary operator expected
如果想在 [] 内避免这种情况,需要将变量用双引号包裹:
$ filename=”nonexistent file”
$ [ ! -e “$filename” ] && echo ”File doesn’t exist”
File doesn’t exist
总结而言,[[ 是增强版的 [。如果追求绝对的兼容性,那么应使用 [,但是一般而言追求方便,使用 [[ 即可。