linux shell 编程:文件判断详细解释

介绍

Shell 中文件判断有三种写法:

  1. test 表达式
  2. [ 表达式 ] ([ 就是 test 命令,左右必须空格)
  3. [[ 表达式 ]] (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(硬链接)
! 非 &&与 ||或