Bash:单括号与双括号的区别
原文:Differences Between Single and Double Brackets in Bash
概述
当我们在 Bash 中做变量比较时,通常可以交换地使用单括号 [] 和双括号 [[]]。比如,我们可以使用表达式 [ 3 -eq 3 ] 或 [[ 3 -eq 3 ]] 来比较 3 是否等于 3。两个表达式都会执行成功,那两者的区别是什么呢?
在本文中,我们会讨论单括号和双括号之间的一些区别。
主要区别
在本节中,我们会讨论单括号和双括号之间的主要区别。
单括号
在 Unix 和 Linux 中,[ 是用于执行表达式的内置命令,我们可以使用 type 命令进行验证:
[ 是 test 内置命令的替代,两者可以交换使用:
[ 和 test 的唯一区别在于:使用 [ 时,需要以 ] 结尾,并且括号前后需要包含空格。
双括号
[[]] 是由
Korn Shell
第一次引入,其增强了 [] 在脚本中做比较、测试的功能,我们可以认为它是 [] 的增强版。
在 Bash 和 zsh 中,我们可以使用 [[]] 的方式,但脚本可能不向后兼容 POSIX。
[[ 是 shell 的一个关键字,让我们再次使用 type 命令进行验证:
其它区别
在本节中,我们会讨论单括号和双括号之间的其它区别。
比较操作符
在 [[]] 中可以使用比较操作符,如 >、< 等,如下:
上述命令中,我们使用 < 符号来检查 1 是否小于 2,命令是可以运行。但如果使用 [] 时,命令会报错:
在这种情况下,Bash 会认为 < 是一个重定向符。因此,我们需要使用转义符 \ 进行转义:
现在,使用 [] 也可以执行成功。
类似的,对于 > 符号也需要使用转义符 \ 进行转义。
对整数比较符 -eq、-ne、-gt、-lt、-ge 和 -le,[] 和 [[]] 都可以正常比较,如下:
布尔操作符
在 [[]] 中,我们可以使用逻辑运算 && 和 ||,如下:
但是在 [] 中,我们必须使用 -a、-o 分别代替 && 和 ||,如下:
聚合表达式
在 [[]] 中,我们可以使用括号 () 来聚合多个表达式,() 的使用可以让脚本更具可读性,如下:
上述命令中,我们使用了 () 对表达式 2 -eq 2 && 1 -eq 1 做了聚合,然后将其作为第 2 个表达式参与到 && 运算中,最后结果为验证为真。
但如果在 [] 中使用 (),则会报语法错误,如下:
上述 [] 中,我们使用 -a 来代替 && 但还是得到了一个报错。
在这里,我们必须使用转义符对括号进行转义,并且前后要保留一个空格,如下:
通过上面的改造,命令就可以成功执行。
模式匹配
在 [[]] 中,我们还可以使用通配符进行模式匹配,如下:
name=Alice:完成变量赋值- 使用
$name = *c*检查变量中是否包含了c $?为 0 表示成功执行
如果把 [[]] 换成 [] 就无法成功执行,如下:
在上述命令中,我们用 [] 代替了 [[]],运行就会出错,这是因为 [ 本身是内置的 Shell 命令,而该命令不支持这么多的参数。
正则表达式
正则表达式是另一种字符串模式匹配的方式,在 [[]] 中,我们可以使用正则表达式来做模式匹配的工作。
首先,我们将值 “Alice” 赋值给 name 变量。然后,我们使用正则表达式来检查变量是否以 Ali 开头,其中 =~ 操作符可以用于正则表达式的匹配、^ 符号表示开头。最后,终端输出了第 2 个命令的执行结果。
那如果在 [] 中使用正则表达式呢?
我们得到了一个错误,所以得到结论:在 [] 中不能使用正则表达式。
单词分割
在 [[]] 中,Bash 不会对值中的单词进行分割,比如变量的值是一个包含空格的字符串,Bash 不会将其分割成多个单词。
上面命令中,我们用一个不存在的文件作为示例,检查文件是否存在,但是值包含字符串。在 [[]] 中,我们可以直接使用 filename 变量,那在 [] 又如何?
上面命令中,我们得到了一个错误。如果希望在 [] 也能使用带空格的字符串,需要加上双引号,如下:
结论
在本文中,我们讨论了单方括号和双方括号在 Bash 中的区别。
[ 是内置的命令,并且其历史要久于 [[,作为后继者的 [[]] 是 [] 的增强版本。如果希望脚本更具兼容性,推荐使用 [],如果希望脚本更具可读性,推荐使用 [[]]。
在示例中,我们看到在 [] 和 [[]] 中都可以使用比较操作符、布尔操作符以及聚合表达式,但也有一些区别。另外,正则表达式和单词分割只有能在 [[]] 中使用。
示例代码可在 Github 地址 中查看。