[ ] 是 test 的语法糖,[[ ]] 是 Bash 原生关键字:前者为命令需空格和终止符,后者为关键字不启新进程、更安全;[ ] 仅字面比较且无正则,[[ ]] 支持模式匹配与正则;逻辑运算上前者用 -a/-o,后者用 &&/||;跨 shell 兼容选 [ ],Bash 专用优先 [[ ]]。
![shell条件测试:掌握test命令与[]、[[]]的差异](https://img.php.cn/upload/article/001/242/473/178174479994427.png)
Shell条件测试中,test、[ ] 和 [[ ]] 看似功能重叠,实则定位不同:[ ] 是 test 的语法糖,而 [[ ]] 是 Bash 原生关键字,不启动新进程、更安全、功能更强。选错语法可能引发空变量报错、模式匹配失败或跨 Shell 兼容问题。
本质与执行机制不同
[ ] 和 test 都是命令(内置或外部),需严格遵循命令解析规则:每个词之间必须有空格,] 是必需的终止符;而 [[ ]] 是 shell 关键字,由解释器直接处理,不经过 exec 调用,因此无参数分词风险,也不依赖 /usr/bin/[ 等外部路径。
- [ -n "$var" ]:依赖引号防空值,否则变成 [ -n ] → 参数不足报错
- [[ -n $var ]]:即使 $var 为空,也安全求值,无需引号
- sudo test -f /etc/passwd 可行;sudo [ -f /etc/passwd ] 往往失败,因多数系统无 /usr/bin/[
字符串与模式匹配能力差异明显
[ ] 仅支持字面量比较(=、!=),且不识别通配符;[[ ]] 支持 == 和 = 的模式匹配语义,并能区分加引号(精确匹配)与不加引号(glob 展开)。
- [ "$file" = "*.log" ]:只比是否字面等于星号字符串
- [[ $file == *.log ]]:匹配任意以 .log 结尾的文件名
- [[ $file == "$pattern" ]]:$pattern 若为 *.log,则按字面匹配,不展开
- [[ $email =~ ^[a-z]+@.*\..*$ ]]:唯一支持正则匹配的语法,[ ] 完全不支持
逻辑运算符和可读性差距显著
[ ] 中必须用 -a(与)、-o(或)、!(非),嵌套复杂易出错;[[ ]] 直接支持 &&、||、! 和括号分组,接近高级语言习惯。
- [ -d "$dir" -a -r "$dir" ]:传统写法,空变量未引号即崩溃
- [[ -d $dir && -r $dir ]]:结构清晰,变量裸写也安全
- [[ ( $x -gt 0 ) && ( $y -lt 100 ) ]]:括号提升优先级,无需额外 test 嵌套
兼容性与使用建议
若脚本需在 dash、ash 等 POSIX shell 下运行,只能用 [ ] 或 test;若明确运行于 Bash/Zsh,优先用 [[ ]] ——它更健壮、表达力强、不易出错。数值比较可用 (( )),但注意它只处理整数算术,不适用于文件或字符串测试。
- 通用脚本(跨 shell):用 [ "$var" = "val" ],始终加引号
- Bash 专用脚本:用 [[ $var == prefix* ]],省引号、加模式、用 &&
- 避免混用:不要在同一个 if 中交替使用 [ ] 和 [[ ]],逻辑边界易混淆

















