Shell test 命令

Shell test 命令详解(新手详细版)

本文档面向零基础新手,从“test 是干什么的、和 [ ] 有什么关系”讲起,详细说明文件测试、字符串比较、数值比较、逻辑组合、在 if/while 中的用法等,并配有大量示例。


一、test 是什么?

1.1 一句话理解

test 是一条命令,用来判断一个条件是否成立:条件为真时,test 的退出码是 0;条件为假时,退出码是 1
不往屏幕输出结果,只通过退出码告诉 Shell“真”或“假”,所以常和 ifwhile&&|| 一起用。

  • → 退出码 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

八、常见坑与建议

  1. [ ] 内侧必须有空格:写 [ 条件 ] ,不能 [条件][ 条件](] 前没空格)。
  2. =、!= 两边要有空格 [ “$a” = “b” ] ,不能 “$a”=”b”
  3. 变量加双引号“$var”,否则未设置或含空格时可能语法错误或误判。
  4. 数字比较用 -eq 等:在 [ ] 里用 -eq、-gt,不用 =>
  5. test 是命令[ ] 是 test 的另一种形式,所以 [、] 和条件之间、多个条件之间都要有空格。
  6. 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;常与 ifwhile&&|| 一起用。
  • 文件-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流程控制.mdShell变量.md 一起用,test 就能用熟。


文档以 POSIX test 及 Bash 的 [ ]、[[ ]] 为准;部分选项在纯 sh 中可能不存在。

发表评论