在 Shell 脚本中,条件判断是控制流程的基础。一个最常见的需求是检查“某个文件是否存在”或“两个字符串是否相等”。这套功能由 test 命令及它的别名 [ 提供。
1. test 与 [ 是同一个命令
test 是一个用于条件测试的独立命令,而 [ 是它的一个符号化别名。当你在脚本中看到:
if [ -f /etc/passwd ]; then
echo "文件存在"
fi
等价于:
if test -f /etc/passwd; then
echo "文件存在"
fi
[ 只是一个普通的命令,它要求最后一个参数必须是 ],否则会报错。正是这个设计让条件表达式在代码中看起来更直观。
2. 常用的测试标志
所有测试条件都在 test/[ 的“参数”位置上,以短选项的形式出现。按用途大致分为三类:
文件测试
| 条件 | 含义 |
|------|------|
| -f 文件 | 文件存在且为普通文件 |
| -d 目录 | 目录存在 |
| -e 路径 | 路径存在(不限类型) |
| -r 文件 | 文件存在且可读 |
| -w 文件 | 文件存在且可写 |
| -x 文件 | 文件存在且可执行 |
| -s 文件 | 文件存在且大小大于 0 |
示例:
if [ -d /tmp ]; then
echo "/tmp 是一个目录"
fi
字符串测试
| 条件 | 含义 |
|------|------|
| -z 字符串 | 字符串长度为 0(为空) |
| -n 字符串 | 字符串长度大于 0(非空) |
| 字符串1 = 字符串2 | 两字符串相等 |
| 字符串1 != 字符串2 | 两字符串不等 |
示例:
name=""
if [ -z "$name" ]; then
echo "变量 name 为空"
fi
数值比较
| 条件 | 含义 |
|------|------|
| 整数1 -eq 整数2 | 等于(equal) |
| 整数1 -ne 整数2 | 不等于(not equal) |
| 整数1 -gt 整数2 | 大于(greater than) |
| 整数1 -lt 整数2 | 小于(less than) |
| 整数1 -ge 整数2 | 大于或等于 |
| 整数1 -le 整数2 | 小于或等于 |
示例:
count=5
if [ $count -gt 0 ]; then
echo "count 为正数"
fi
3. 组合多个条件
! 表达式:逻辑非表达式1 -a 表达式2:逻辑与(and)表达式1 -o 表达式2:逻辑或(or)
也可直接用 && 和 || 连接两个 test 命令(不在单个 [ ] 内部):
[ -f file ] && [ -r file ] && echo "可读文件"
4. [ ] 与 [[ ]] 的区别
在 Bash 和其他一些高级 Shell 中,还有 [[ ]] 扩展语法。它的优势在于:
- 支持
&&、||直接在[[ ]]内部使用,比-a、-o更清晰; - 支持正则匹配(如
[[ $str =~ ^[0-9]+$ ]]); - 不需要对变量使用双引号保护(在
[[ ]]里空变量不会导致语法错误)。
但在追求最大兼容性(如 #!/bin/sh)的脚本中,通常只能使用 test/[ ]。
5. 安全注意事项:始终给变量加上双引号
当使用 [ ] 时,必须给变量加双引号,否则变量为空或包含空格时会导致语法错误或判断异常:
# 错误写法(当 name 为空时,脚本报错)
if [ $name = "root" ]; then ...
# 正确写法
if [ "$name" = "root" ]; then ...
而 [[ ]] 则无需如此,因为它是一个 Shell 关键字,具备更智能的解析规则。
6. 在一行命令中使用 && 和 ||
正因为 test 是一个命令,它可以作为一行命令中的条件控制:
[ -d /backup ] && tar -czf /backup/data.tgz /data || echo "备份目录不存在"
如果 [ -d /backup ] 成功,执行压缩;否则输出错误信息。这种写法在简单的运维脚本里十分常见,可读性高且简洁。
总之,test/[ ] 是 Shell 脚本的逻辑基石。掌握文件、字符串、数值三类判断,注意变量引号,并根据环境选择 [ ] 或 [[ ]],就能写出安全且清晰的自动化脚本。