shell 判断文件是否存在(最佳实践)

Shell 判断文件是否存在:从入门到实战

在日常的 Linux 系统运维和自动化脚本开发中,我们常常需要判断某个文件是否存在。这个看似简单的操作,却贯穿了从基础脚本编写到复杂系统逻辑设计的全过程。比如你在写一个备份脚本时,必须先确认源文件是否存在,否则执行备份操作就会失败甚至引发错误。这就是“shell 判断文件是否存在”这一核心能力的价值所在。

想象一下,你正在整理一个文件夹,但不确定某个配置文件是否已经存在。如果你不先检查,直接执行写入操作,可能会覆盖已有内容,造成数据丢失。所以,提前判断文件是否存在,就像开车前检查油量和轮胎一样,是一种必要的安全习惯

接下来,我会带你一步步掌握 shell 中判断文件是否存在的方式,从最基础的语法开始,到实际应用场景,最后给出最佳实践建议。


基本语法:使用 [ -f 文件名 ] 判断

在 shell 脚本中,最常见、最推荐的方式是使用方括号 [ ] 配合 -f 选项来判断文件是否存在。

if [ -f /etc/passwd ]; then
    echo "文件存在,可以安全读取"
else
    echo "文件不存在,请检查路径或权限"
fi

代码说明:

  • [ -f /etc/passwd ]:这是判断命令,-f 表示“是否为普通文件”(regular file)
  • if ... then ... else ... fi:标准的条件判断结构
  • echo:输出提示信息,用于调试或用户反馈

⚠️ 注意:方括号 [] 之间必须有空格,否则会报错。比如 [ -f file ] 是正确的,而[-f file] 会出错。


更多判断选项:区分文件类型

有时候,我们不仅想知道文件是否存在,还想知道它是什么类型的。shell 提供了多个判断标志,适用于不同场景。

判断标志 含义 适用场景
-f 是否为普通文件 配置文件、日志文件等
-d 是否为目录 检查项目根目录是否存在
-e 是否存在(文件或目录) 通用判断,最宽松
-r 是否可读 检查权限是否允许读取
-w 是否可写 检查是否有写入权限
-x 是否可执行 判断脚本或程序能否运行
if [ -d /home/user/data ]; then
    echo "目录存在,可以进入"
else
    echo "目录不存在,需要先创建"
fi

if [ -f /etc/hosts ] && [ -r /etc/hosts ]; then
    echo "配置文件存在且可读"
else
    echo "文件不存在或无读取权限"
fi

💡 小贴士:-e 是最宽松的判断,只要路径存在就返回真,无论它是文件、目录还是链接。在不确定类型时,-e 是安全的选择。


实际应用案例:自动化部署脚本

我们来看一个真实场景:部署一个 Web 项目时,需要检查 dist/ 目录是否已生成,然后决定是否执行构建。

#!/bin/bash

PROJECT_DIR="/var/www/myapp"
DIST_DIR="$PROJECT_DIR/dist"

if [ -d "$DIST_DIR" ]; then
    echo "✅ 发布目录存在,准备替换文件..."
    # 进行文件替换操作(示例)
    cp -r "$DIST_DIR"/* "$PROJECT_DIR/html/"
else
    echo "❌ 发布目录不存在,请先运行构建命令"
    echo "建议执行:npm run build"
    exit 1  # 脚本退出,返回错误码
fi

echo "部署完成,服务已更新"

关键点解析:

  • 使用变量存储路径,提高可维护性
  • "$DIST_DIR" 加引号,防止路径中含空格导致错误
  • exit 1 表示脚本执行失败,可用于 CI/CD 系统判断

这个例子展示了“shell 判断文件是否存在”在实际工程中的重要性——它决定了后续逻辑是否能安全执行。


使用 test 命令的等价写法

除了 [ ],shell 还提供了 test 命令,功能完全等价,但语法更灵活。

if test -f /etc/resolv.conf; then
    echo "DNS 配置文件存在"
else
    echo "DNS 配置文件缺失"
fi

✅ 两者等价,[ -f file ] 实际上是 test -f file 的简写形式。选择哪种取决于个人风格,但 [ ] 更常见于脚本中。


高级技巧:结合 ||&& 实现快速响应

你可以利用逻辑运算符简化判断逻辑,实现“存在则执行,否则提示”的效果。

[ -f /etc/myapp.conf ] && source /etc/myapp.conf || echo "使用默认配置"

[ -f /var/log/app.log ] || touch /var/log/app.log

[ -z "$1" ] && echo "请提供输入文件路径" && exit 1

说明:

  • && 表示“前一个命令成功时执行下一个”
  • || 表示“前一个命令失败时执行下一个”
  • -z 判断字符串是否为空(空字符串返回真)

这种写法简洁高效,非常适合在脚本开头做参数校验或初始化。


常见陷阱与解决方案

1. 路径中含空格的问题

if [ -f /home/user/my file.txt ]; then
    echo "文件存在"
fi

if [ -f "/home/user/my file.txt" ]; then
    echo "文件存在"
fi

⚠️ 原因:shell 会把 my file.txt 拆成两个参数,导致命令报错。

2. 路径不存在但脚本继续执行

[ -f /nonexistent/file ] && echo "存在" || echo "不存在"

3. 变量未定义导致错误

if [ -f $CONFIG_FILE ]; then
    echo "配置文件存在"
fi

if [ -n "$CONFIG_FILE" ] && [ -f "$CONFIG_FILE" ]; then
    echo "配置文件存在"
else
    echo "配置文件路径未设置或不存在"
fi

最佳实践总结

  1. 始终使用引号包裹路径变量,防止空格或特殊字符引发问题
  2. 优先使用 -f 判断普通文件,-d 判断目录,-e 判断存在性
  3. 在脚本开头做输入校验,避免执行到一半才发现问题
  4. 合理使用 &&||,让脚本更紧凑高效
  5. 添加清晰的错误提示信息,方便调试和运维

结语

“shell 判断文件是否存在”看似简单,却是编写健壮脚本的基石。无论是日常运维、CI/CD 流水线,还是自动化部署,掌握这一技能都能让你的脚本更加安全、可靠。

就像盖房子要先打地基,写脚本也必须先判断环境条件是否满足。当你能在脚本中自然地使用 if [ -f file ] 这类判断语句时,你就真正迈入了 shell 脚本开发的进阶门槛。

从今天起,把“判断文件是否存在”当作每个脚本的第一步,你会发现自己的脚本不再轻易崩溃,反而越来越稳定、越来越智能。