一、背景知识
[ ] 源于 1970 年代的 Bourne shell(test 命令),而 [[ ]] 是 1980 年代 ksh 的创新,后被 Bash 采纳。现代 Bash 中 [ 已是内置命令,但处理逻辑仍保持 POSIX 兼容性。
现代 Bash 脚本(#!/bin/bash),优先使用 [[]](更安全、功能更强)。
POSIX 兼容脚本(#!/bin/sh),使用 [] 并严格遵循很多规则,如:
[ -n "$var" ] && [ "$var" != "ERROR" ]
#所有变量加双引号
#逻辑组合用 && 或 || 连接多个 []
二、关键区别详解及实例
1、字符串比较(含空变量)
str="Hello World"
empty=""
# [ ] 必须加引号,否则空变量报错
if [ "$empty" = "" ]; then # 正确写法
echo "[]: Empty string"
fi
# [[ ]] 自动处理空变量
if [[ $empty == "" ]]; then # 无需引号
echo "[[]]: Empty string"
fi
2、模式匹配(通配符)
file="image.jpg"
# [[ ]] 支持通配符扩展
if [[ $file == *.jpg ]]; then
echo "[[]]: JPEG file"
# [ ] 不支持通配符(需外部命令如 `case`)
if [ "$file" = "*.jpg" ]; then # 字面比较 *.jpg
echo "[]: This will NOT match"
fi
3、正则表达式匹配(仅 [[]] 支持)
email="user@example.com"
if [[ $email =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
echo "[[]]: Valid email"
fi
4、逻辑运算符
num=15
# [] 必须用 -a/-o(或转义 &&/||)
if [ $num -gt 10 -a $num -lt 20 ]; then
echo "[]: 10 < num < 20"
# [[]] 支持原生 && 、||
if [[ $num > 10 && $num < 20 ]]; then
echo "[[]]: 10 < num < 20 "
fi
5、数字运算
a=10
b=2
# [] 必须用 -gt/-lt
if [ $a -gt $b ]; then
echo "[]: a > b"
# [[]] 支持数学符号(但实际按字符串比较!)
if [[ $a > $b ]]; then # 按字典序比较,"10" < "2"!
echo "This may be WRONG: [[ 10 > 2 ]] is false!"
fi
# 正确方式(数字比较统一用 -gt/-lt)
if [[ $a -gt $b ]]; then
echo "[[]]: Correct: a > b"
fi
6、路径扩展问题
touch "a b.txt" # 创建含空格的文件
# [] 可能误触发路径扩展
if [ -f *.txt ]; then # 若匹配多个文件,报错:[: too many arguments
echo "This may fail"
fi
# [[]] 禁用路径扩展
if [[ -f *.txt ]]; then # *.txt 被视为字面字符串
echo "Safe: [[ -f *.txt ]] checks a file named '*.txt'"
fi