test -f "$FILE" 判断普通文件存在且为文件,需引号防空格错误;-e 判断任意存在,-f 不追踪软链接目标;[[ ]] 更安全但非 POSIX;&&/|| 可替代 if 实现简洁判断。

test 命令判断文件是否存在,最常用也最容易写错
直接用 test -f /path/to/file 就能判断普通文件是否存在且为文件(不是目录、设备等)。但很多人卡在「明明文件在那儿,却返回 false」——通常是因为路径含空格、变量未引号包裹,或误用了 -e 和 -f 的语义差别。
常见错误现象:test -f $FILE 在 $FILE="my file.txt" 时直接报错 test: too many arguments,因为 shell 把空格当参数分隔符了。
- 始终给变量加双引号:
test -f "$FILE" -
-f只认「存在且是普通文件」;-e是「存在即可」(包括目录、符号链接、设备文件) - 符号链接要小心:
-f对软链接本身返回 true,但若链接目标不存在,它仍返回 true —— 它不追踪目标 - 想确认「存在且可读」?连用:
test -f "$FILE" && test -r "$FILE",别试图塞进一个test里
bash 中的 [[ ]] 比 test 更安全,但语法细节不能乱套
[[ -f "$FILE" ]] 功能和 test -f "$FILE" 一样,但内部做了词法解析优化,对未引号变量、通配符、空格更宽容。不过它不是 POSIX 兼容的,别在 /bin/sh 脚本里用。
使用场景:写 bash 专属脚本(如 #!/bin/bash 开头),需要简洁、少出错。
-
[[内部变量自动展开,[[ -f $FILE ]]即使没引号也通常不会崩(但依然建议引) - 支持正则匹配:
[[ $FILE =~ \.log$ ]],但注意=~右侧不能加引号 - 不能用
[[ -f /dev/null ]]判断设备文件是否存在 ——-f仍要求是普通文件,得用-e - 别混用
[(单中括号)和[[:前者是外部命令,后者是 shell 关键字,行为有差异
一行判断并执行,别用 if 写三行
不需要为了「判断+执行」专门写 if 块。shell 的 && 和 || 是天然搭档,写出来干净又符合直觉。
常见错误现象:有人写 if [ -f file ]; then echo ok; fi,其实只是为了打个日志或赋个值,完全没必要。
- 存在就运行:
[ -f "$CONFIG" ] && ./start.sh - 不存在就退出:
[ -f "$BIN" ] || { echo "missing binary"; exit 1; } - 注意
&&和||的短路逻辑:前面失败才执行后面,别反着用 - 大括号里的多条命令必须用分号结尾,且
{后、}前要有空格
stat 或 ls 配合 grep 是调试手段,不是判断主力
当你不确定 test 为啥返回 false,或者想看文件权限、链接目标、inode 等细节,才用 stat 或 ls -l。它们不能替代 test 做逻辑判断——输出是字符串,解析成本高、不可靠。
使用场景:排查为什么 -f 不生效,比如怀疑是符号链接断链、ACL 限制、挂载点异常等。
-
stat "$FILE"会明确告诉你类型(regular file / directory / symbolic link)和访问权限 -
ls -l "$FILE"看第一列字符:开头是-才算普通文件,d是目录,l是链接 - 别用
ls | grep xxx判断存在性 —— 文件名含换行或特殊字符时会误判,而且效率低 -
stat在某些嵌入式系统或容器里可能没有,test几乎一定有
真正容易被忽略的是:test -f 对符号链接的处理方式,以及变量未引号在不同 shell 下的行为漂移。哪怕只是写个本地脚本,也别省那对双引号。









