[[ ]]
是 Bash、Zsh 和 Ksh 等现代 Shell 提供的增强型条件测试结构,它比传统的 [ ]
更强大且更安全。下面我将全面解析 [[ ]]
的功能和用法。
基本概念
[[
和]]
是 Shell 关键字(不是命令)- 提供比
[ ]
更丰富的功能集 - 不会进行单词分割和路径名扩展
- 支持更自然的语法(如不需要引号保护变量)
基本语法
if [[ 条件表达式 ]]; then
# 条件为真时执行的命令
fi
1. 字符串比较
操作符 | 说明 |
---|---|
== 或 = | 字符串相等 |
!= | 字符串不相等 |
< | 按字典序小于(无需转义) |
> | 按字典序大于(无需转义) |
=~ | 正则表达式匹配(Bash 3.0+) |
== (带通配符) | 模式匹配 |
示例:
name="example.txt"
# 字符串相等
if [[ "$name" == "example.txt" ]]; then
echo "文件名匹配"
fi
# 模式匹配(通配符)
if [[ "$name" == *.txt ]]; then
echo "是文本文件"
fi
# 正则表达式匹配
if [[ "$name" =~ ^ex.*\.txt$ ]]; then
echo "符合正则表达式"
fi
# 字典序比较
if [[ "apple" < "banana" ]]; then
echo "apple 在 banana 之前"
fi
2. 数值比较
可以直接使用数学比较符号(不需要 -eq
等形式):
操作符 | 说明 |
---|---|
== | 等于 |
!= | 不等于 |
< | 小于 |
> | 大于 |
<= | 小于等于 |
>= | 大于等于 |
示例:
num=10
if [[ num -eq 10 ]]; then # 传统方式仍可用
if [[ num == 10 ]]; then # 更直观的方式
if (( num == 10 )); then # 算术比较的最佳方式
if [[ $num > 5 ]]; then
echo "数字大于5"
fi
3. 文件测试
与 [ ]
相同的文件测试操作符:
操作符 | 说明 |
---|---|
-e | 文件存在 |
-f | 是普通文件 |
-d | 是目录 |
-s | 文件非空 |
-r | 可读 |
-w | 可写 |
-x | 可执行 |
-L | 是符号链接 |
-O | 属于当前用户 |
-G | 属于当前用户的组 |
-N | 自上次读取后被修改 |
file1 -nt file2 | file1 比 file2 新 |
file1 -ot file2 | file1 比 file2 旧 |
示例:
file="/path/to/file"
if [[ -e "$file" ]]; then
echo "文件存在"
fi
if [[ -f "$file" && -s "$file" ]]; then
echo "是普通文件且非空"
fi
4. 逻辑运算符
更自然的逻辑运算符:
操作符 | 说明 |
---|---|
&& | 逻辑与 |
|| | 逻辑或 |
! | 逻辑非 |
示例:
if [[ -d "$dir" && -w "$dir" ]]; then
echo "目录存在且可写"
fi
if [[ ! -f "$lockfile" ]]; then
echo "锁文件不存在"
fi
5. 高级特性
模式匹配
name="file123.txt"
if [[ "$name" == file*.txt ]]; then
echo "匹配 file*.txt 模式"
fi
正则表达式匹配
email="user@example.com"
if [[ "$email" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
echo "有效的电子邮件地址"
fi
自动变量引用
不需要引号保护变量:
filename="my file.txt"
# 在 [ ] 中会出错
if [ -f $filename ]; then ... # 错误!
# 在 [[ ]] 中安全
if [[ -f $filename ]]; then ... # 正确
6. [[ ]]
与 [ ]
的关键区别
特性 | [[ ]] | [ ] |
---|---|---|
类型 | Shell 关键字 | 命令(通常是内置或外部) |
单词分割 | 不会进行 | 会进行 |
路径名扩展 | 不会进行 | 会进行 |
变量引用 | 不需要引号 | 必须使用引号 |
模式匹配 | 支持 (== , =~ ) | 不支持 |
逻辑运算符 | 使用 && , || , ! | 使用 -a , -o , ! |
字符串比较运算符 | == , != , < , > | = , != (需转义 < , > ) |
数值比较 | 可直接用 < , > 等 | 必须用 -lt , -gt 等 |
POSIX 兼容性 | 不兼容 | 兼容 |
7. 最佳实践
-
优先使用
[[ ]]
:- 在 Bash 脚本中优先使用
[[ ]]
,它更安全、功能更强大 - 只在需要 POSIX 兼容性时使用
[ ]
- 在 Bash 脚本中优先使用
-
变量引用:
- 在
[[ ]]
中可以不加引号,但为了代码清晰仍建议加引号
if [[ "$var" == value ]]; then
- 在
-
复合条件:
- 使用
&&
和||
代替-a
和-o
if [[ -f "$file" && -r "$file" ]]; then
- 使用
-
模式匹配:
- 使用
==
进行通配符匹配 - 使用
=~
进行正则匹配
- 使用
-
数值比较:
- 对于算术比较,
(( ))
通常是最佳选择
if (( num > 10 )); then
- 对于算术比较,
8. 实际应用示例
- 检查命令是否成功:
if [[ $(command) == "expected output" ]]; then
echo "命令输出符合预期"
fi
- 安全的文件处理:
file="some file.txt"
if [[ -e "$file" && ! -d "$file" ]]; then
echo "文件存在且不是目录"
fi
- 高级字符串检查:
input="12345"
if [[ "$input" =~ ^[0-9]+$ ]]; then
echo "输入全是数字"
fi
- 多条件判断:
hour=$(date +%H)
if [[ $hour -ge 8 && $hour -lt 18 ]]; then
echo "工作时间"
elif [[ $hour -ge 18 || $hour -lt 8 ]]; then
echo "非工作时间"
fi
总结
[[ ]]
是现代 Shell 脚本中条件测试的首选工具,它提供了:
- 更安全的变量处理
- 更丰富的比较功能
- 更直观的语法
- 更强大的模式匹配能力