Shell test 命令详解(新手详细版)
本文档面向零基础新手,从“test 是干什么的、和 [ ] 有什么关系”讲起,详细说明文件测试、字符串比较、数值比较、逻辑组合、在 if/while 中的用法等,并配有大量示例。
一、test 是什么?
1.1 一句话理解
test 是一条命令,用来判断一个条件是否成立:条件为真时,test 的退出码是 0;条件为假时,退出码是 1。
它不往屏幕输出结果,只通过退出码告诉 Shell“真”或“假”,所以常和 if、while、&&、|| 一起用。
- 真 → 退出码 0
- 假 → 退出码 1
- 若语法错误或参数不对,可能返回大于 1 的退出码
1.2 test 和 [ ] 是一回事
下面两种写法完全等价:
test -f /etc/passwd
[ -f /etc/passwd ]
- [ ] 其实是命令[ 的另一种写法;[ 和 ] 是命令名和最后一个参数,所以 ] 前、[ 后必须有空格。
- 写 if [ … ] 时,本质就是在用 test 判断条件。
注意:[ 和 ] 与里面的条件之间必须有空格,不能写成 [-f file]。
1.3 [[ ]](Bash 专用)
[[ ]] 是 Bash 的关键字,不是命令;支持更多写法(如 &&、||、=~ 正则),且不必对某些符号加引号。
本文以 test / [ ] 为主,需要时说明 [[ ]] 的差异。
二、基本用法:怎么“看到”真和假
test 不输出文字,只改退出码;用 $? 可以看上一条命令的退出码:
test -f /etc/passwd
echo $?
# 0(表示“真”,文件存在且为普通文件)
test -f /不存在的路径
echo $?
# 1(表示“假”)
在 if 里,Shell 就是根据 test(或 [ ])的退出码决定走 then 还是 else:
if test -f /etc/passwd; then
echo "文件存在"
else
echo "文件不存在"
fi
# 文件存在
if [ -d /tmp ]; then
echo "/tmp 是目录"
fi
# /tmp 是目录
三、文件与路径测试
以下选项都写 test 选项 路径 或 [ 选项 路径 ];路径建议加双引号(如 “$file”),避免空或含空格出错。
3.1 存在与类型
| 选项 | 含义 |
|---|---|
| -e | 路径存在(文件或目录均可) |
| -f | 存在且为普通文件 |
| -d | 存在且为目录 |
| -L | 存在且为符号链接(也写 -h) |
| -b | 块设备 |
| -c | 字符设备 |
| -p | 命名管道 |
| -S | 套接字 |
示例:
[ -f /etc/passwd ] && echo "是文件"
[ -d /tmp ] && echo "是目录"
[ -e /home ] && echo "存在"
3.2 权限与属性
| 选项 | 含义 |
|---|---|
| -r | 存在且当前用户可读 |
| -w | 存在且当前用户可写 |
| -x | 存在且当前用户可执行 |
| -s | 存在且大小大于 0(非空文件) |
| -N | 自上次读入后被修改过(部分 Shell) |
示例:
[ -r "$file" ] && echo "可读"
[ -w "$file" ] && echo "可写"
[ -s "$file" ] && echo "非空"
3.3 归属(Bash 等)
| 选项 | 含义 |
|---|---|
| -O | 当前用户是属主 |
| -G | 当前用户属于属组 |
3.4 两个路径比较
| 写法 | 含义 |
|---|---|
| 路径1 -nt 路径2 | 1 比 2 新(修改时间更晚) |
| 路径1 -ot 路径2 | 1 比 2 旧 |
| 路径1 -ef 路径2 | 同一文件(同一设备同一 inode,或同一路径) |
示例:
[ file1.txt -nt file2.txt ] && echo "file1 更新"
[ /tmp -d ] && [ -r /tmp ] && echo "是目录且可读"
四、字符串测试
4.1 是否为空:-z、-n
- -z “串”:串长度为 0(未设置或空)则为真。
- -n “串”:串长度非 0 则为真。
注意:变量要加双引号,否则未设置时会变成 [ -z ] 等错误形式。
s=""
[ -z "$s" ] && echo "为空"
# 为空
s="hello"
[ -n "$s" ] && echo "非空"
# 非空
unset s
[ -z "$s" ] && echo "未设置或空"
# 未设置或空
4.2 相等与不等:=、!=
- “串1” = “串2”:相等为真(= 两边要有空格)。
- “串1” != “串2”:不相等为真。
a="yes"
[ "$a" = "yes" ] && echo "相等"
[ "$a" != "no" ] && echo "不相等"
再次强调:[ “$a” = “yes” ] 里,= 两边、[ 和 ] 内侧都要有空格;变量用 “$a” 避免空或含空格出错。
4.3 在 [[ ]] 里:==、、=~
在 [[ ]] 中可以用 ==、!=,以及 <、>(按字典序);=~ 表示右边是正则,左边是否匹配。
[[ "$path" =~ ^/home ]] && echo "在 /home 下"
[[ "$x" == "ok" ]] && echo "是 ok"
五、数值比较
在 test / [ ] 里比较数字必须用下面这些,不能用 =、<、>(会当字符串比较):
| 选项 | 含义 |
|---|---|
| -eq | 等于(equal) |
| -ne | 不等于(not equal) |
| -gt | 大于(greater than) |
| -ge | 大于等于 |
| -lt | 小于(less than) |
| -le | 小于等于 |
示例:
n=10
[ "$n" -eq 10 ] && echo "等于 10"
[ "$n" -gt 5 ] && echo "大于 5"
[ "$n" -le 20 ] && echo "小于等于 20"
变量建议加引号;若可能为空,先判断 -z 或保证有默认值,再比较,避免 [ -gt 5 ] 这种错误。
六、逻辑组合:与、或、非
6.1 在 test / [ ] 里:!、-a、-o
- ! 条件:条件取反(非)。
- 条件1 -a 条件2:与(and),两个都真才真。
- 条件1 -o 条件2:或(or),有一个真就真。
注意:-a、-o 的优先级可能和预期不同,复杂时多用 括号 + -a/-o 或拆成多个 [ ] 用 &&、|| 连接(见下)。
[ -f file.txt -a -r file.txt ] && echo "存在且可读"
[ ! -d /tmp ] && echo "不是目录"
[ "$a" -gt 0 -o "$b" -lt 10 ] && echo "a>0 或 b<10"
括号:在 [ ] 里用 (、) 并保证括号两侧有空格,且通常需用引号或反斜杠保护,避免被 Shell 解析;复杂逻辑更推荐用 [[ ]] 或拆成多句 &&、||。
6.2 用 &&、|| 连接多条 test
不一定要在一个 [ ] 里写满,可以多个 [ ] 用 &&、|| 连接:
[ -f "$file" ] && [ -r "$file" ] && echo "存在且可读"
[ -z "$var" ] || [ "$var" = "yes" ] && echo "空或是 yes"
6.3 在 [[ ]] 里:&&、||、!
[[ ]] 里可以直接写 &&、||、!,不必用 -a、-o:
[[ -f file.txt && -r file.txt ]] && echo "存在且可读"
[[ ! -d /tmp ]] && echo "不是目录"
七、常见写法示例
7.1 判断文件存在且是普通文件
if [ -f "$1" ]; then
echo "$1 是文件"
fi
7.2 判断目录存在且可写
if [ -d "$dir" ] && [ -w "$dir" ]; then
echo "目录存在且可写"
fi
7.3 判断变量非空
if [ -n "$USER" ]; then
echo "用户是 $USER"
fi
7.4 判断变量为空时退出
if [ -z "$1" ]; then
echo "用法: $0 <参数>" >&2
exit 1
fi
7.5 数值范围
if [ "$count" -ge 0 ] && [ "$count" -le 100 ]; then
echo "在 0~100 之间"
fi
7.6 字符串相等
if [ "$mode" = "debug" ]; then
echo "调试模式"
fi
7.7 取反
if [ ! -e "$file" ]; then
echo "不存在"
fi
八、常见坑与建议
- [ ] 内侧必须有空格:写 [ 条件 ] ,不能 [条件] 或 [ 条件](] 前没空格)。
- =、!= 两边要有空格: [ “$a” = “b” ] ,不能 “$a”=”b”。
- 变量加双引号:“$var”,否则未设置或含空格时可能语法错误或误判。
- 数字比较用 -eq 等:在 [ ] 里用 -eq、-gt,不用 =、>。
- test 是命令:[ ] 是 test 的另一种形式,所以 [、] 和条件之间、多个条件之间都要有空格。
- Bash 里可用 [[ ]]:支持 &&、||、=~,可读性更好。
九、选项速查表
9.1 文件/路径
| 选项 | 含义 |
|---|---|
| -e | 存在 |
| -f | 普通文件 |
| -d | 目录 |
| -L、-h | 符号链接 |
| -r、-w、-x | 可读、可写、可执行 |
| -s | 非空(大小>0) |
| -nt、-ot、-ef | 更新、更旧、同一文件 |
9.2 字符串
| 写法 | 含义 |
|---|---|
| -z “串” | 长度为 0 |
| -n “串” | 长度非 0 |
| “串1” = “串2” | 相等 |
| “串1” != “串2” | 不相等 |
9.3 数值(在 [ ] 里)
| 选项 | 含义 |
|---|---|
| -eq、-ne | 等于、不等于 |
| -gt、-ge | 大于、大于等于 |
| -lt、-le | 小于、小于等于 |
9.4 逻辑(在 [ ] 里)
| 写法 | 含义 |
|---|---|
| ! 条件 | 非 |
| 条件1 -a 条件2 | 与 |
| 条件1 -o 条件2 | 或 |
十、小结
- test 和 [ ] 等价,用来判断条件,真退出 0,假退出 1;常与 if、while、&&、|| 一起用。
- 文件:-e、-f、-d、-r、-w、-x、-s、-nt、-ot、-ef 等。
- 字符串:-z、-n、=、!=;变量务必加双引号。
- 数值:-eq、-ne、-gt、-ge、-lt、-le;不用 =、。
- 逻辑:!、-a、-o;或拆成多句用 &&、||;Bash 里 [[ ]] 可写 &&、||、=~。
- 注意 [ ] 和 = 两边空格、变量加引号。
多写几段 if [ … ]、 [ -f “$file” ] && …,再结合 Shell流程控制.md、Shell变量.md 一起用,test 就能用熟。
文档以 POSIX test 及 Bash 的 [ ]、[[ ]] 为准;部分选项在纯 sh 中可能不存在。