介绍
Shell 中文件判断有三种写法:
test 表达式[ 表达式 ]([就是 test 命令,左右必须空格)[[ 表达式 ]](Bash 扩展,更安全,推荐,支持正则,左右也要空格)
语法
写法1
test -f /etc/passwd
写法2(常用)
if [ -f /etc/passwd ]; then
echo "是普通文件"
fi
写法3 bash推荐
if [[ -f /etc/passwd ]]; then
echo "是普通文件"
fi
文件类型判断
| 参数 | 含义 |
|---|---|
-e file |
exists:文件/目录是否存在(不管是什么类型)✅最通用 |
-f file |
file:存在且是普通文件(不是目录、链接、设备) |
-d file |
directory:存在且是目录 |
-L file / -h file |
link:存在且是软链接(符号链接) |
-b file |
block:块设备文件(硬盘、U盘) |
-c file |
character:字符设备(终端 /dev/tty) |
-p file |
命名管道(FIFO) |
-S file |
socket:套接字文件 |
注意:-f /tmp/link 如果是软链接指向普通文件,-f 会跟随链接;-L 只判断本身是不是链接。
文件权限判断
| 参数 | 含义 |
|---|---|
-r file |
当前用户可读 |
-w file |
当前用户可写 |
-x file |
当前用户可执行 |
-u file |
文件有SUID权限(set-user-id) |
-g file |
文件有SGID权限(set-group-id) |
-k file |
文件有粘滞位sticky bit(如/tmp目录) |
注意:权限判断是进程当前用户身份,不是看文件权限字符串字面量。
文件大小判断
| 参数 | 含义 |
|---|---|
-s file |
文件存在且大小 > 0(非空文件) |
-z 字符串 |
字符串为空(不是文件大小! 容易混淆) |
-n 字符串 |
字符串非空 |
示例:
[ -s log.txt ]日志文件不为空
两个文件之间比较
二元判断
[ file1 -nt file2 ]
| 参数 | 含义 |
|---|---|
file1 -nt file2 |
new than:file1 比 file2 更新(修改时间mtime) |
file1 -ot file2 |
old than:file1 比 file2 更旧 |
file1 -ef file2 |
equal file:两个文件inode相同(硬链接,指向同一个文件) |
逻辑组合(与/或/非)
[ ] / test 中用 -a -o !
! [ -f a.txt ] # 取反:不是普通文件
[ -f a.txt -a -r a.txt ] # -a 逻辑与,文件存在且可读
[ -d dir -o -f file ] # -o 逻辑或
⚠️
-a / -o在[ ]里有歧义,不推荐
[[ ]] 推荐用 && || !
if [[ -f "a.txt" && -r "a.txt" ]]; then
echo "存在并且可读"
fi
!取反&&逻辑与||逻辑或
常见坑(重点)
1. [ ] 两边必须空格
[ -f test.txt ] ✅
[-f test.txt ] ❌ 报错!
2. 变量不加引号,文件名带空格会炸
file="my file.txt"
[ -f $file ] # 错误,空格会截断
[ -f "$file" ] # 正确,加双引号
[[ -f $file ]] # bash [[ ]] 内部自动处理,不加引号一般也安全,但建议养成加引号习惯
3. -e 和 -f 区别
-e:只要存在就返回真(目录也会true)-f:必须是普通文件
4. 软链接:
-f、-d、-r跟随软链接,判断链接指向的目标-L只判断本身是不是链接,不跟进目标
例子
#!/bin/bash
path="./test.txt"
if [[ ! -e "$path" ]]; then
echo "文件不存在"
elif [[ -f "$path" ]]; then
echo "是普通文件"
if [[ -r "$path" ]]; then
echo "可读"
fi
if [[ -s "$path" ]]; then
echo "文件非空"
fi
elif [[ -d "$path" ]]; then
echo "这是目录"
fi
总结
-e 存在
-f 普通文件
-d 目录
-L 软链接
-r 可读
-w 可写
-x 可执行
-s 文件>0字节
-nt 更新
-ot 更旧
-ef 同一inode(硬链接)
! 非 &&与 ||或