Linux find 命令从入门到实战:循序渐进训练计划
find 是 Linux
下最强大的文件查找工具之一,但它的参数多、组合灵活,很多初学者望而却步。这篇文章给你一份循序渐进的训练计划:从基础查找到
3 个真实运维场景的完整脚本,跟着练一遍,find
就真正变成你的肌肉记忆了。
准备工作:搭建练习环境
动手之前,先创建一个测试目录,造一些文件用来练手:
mkdir -p ~/find_test && cd ~/find_test
touch file1.txt file2.log .hidden_file script.sh large_file.bin
mkdir -p sub1/sub2
touch sub1/a.txt sub1/sub2/b.log
chmod 777 script.sh建议每学一个命令,都在这个目录里实际跑一遍,看输出是否符合预期。
第一阶段:按名称与类型查找
题目 1:按名称查找
.log 文件
查找当前目录下所有以 .log 结尾的文件:
find . -name "*.log"如果想不区分大小写(比如同时匹配 .LOG),用
-iname:
find . -iname "*.log"题目 2:只查找目录
find . -type d-type 是最常用的过滤条件之一:f
表示普通文件,d 表示目录,l
表示符号链接。
题目 3:查找隐藏文件
Linux 下以 . 开头的是隐藏文件:
find . -name ".*"第二阶段:按大小与时间查找
题目 4:查找大于 10MB 的文件
find . -size +10M-size 的单位很有讲究:+10M 表示大于
10MB,-10M 表示小于 10MB,10M
表示约等于。单位还可以用
k(KB)、G(GB)、c(字节)。
题目 5:查找 24 小时内修改过的文件
find . -mtime -1
# 或者用分钟粒度:
find . -mmin -1440-mtime -1 表示修改时间在 1
天以内,-mmin -1440 是同样的意思(24×60=1440
分钟)。
题目 6:查找 7 天前被访问过的文件
find . -atime +7注意这里是 +7(7 天以前),不是
-7。atime
是访问时间,mtime 是修改时间,ctime
是状态改变时间——三者的区别是面试常客,值得记住。
第三阶段:深度、权限与逻辑组合
题目 7:限制查找深度
只在当前目录下找 .txt
文件,最多深入两层子目录:
find . -maxdepth 2 -name "*.txt"-maxdepth 建议放在其他条件前面,否则在某些 find
实现里会给出警告。
题目 8:在 /var/log 下不区分大小写找日志
find /var/log -iname "*.log"题目 9:按权限查找
查找权限为 777 的文件(安全排查常用):
sudo find /var -perm 777 -ls-perm 777 是精确匹配;-perm -777
表示”至少包含”这些权限位;-perm /777
表示”包含其中任意”。排查可疑文件时 -perm -4000(找
SUID 文件)也很常用。
题目 10:逻辑或组合
查找 .jpg 或 .png 图片:
find /data \( -name "*.jpg" -o -name "*.png" \)括号需要转义(或加引号),否则 shell 会误解。-o
是 OR,-a 是 AND(默认可省略),! 是
NOT。
题目 11:排除 .git 目录
查找所有 .sh 脚本,但跳过
.git:
find . -path "*/.git" -prune -o -name "*.sh" -print这行值得拆开理解,它本质是个 if-else:
-path "*/.git":当前路径是不是.git目录?-prune:如果是,直接剪掉这根”树枝”,不往下递归-o:否则,执行后面的逻辑-name "*.sh" -print:匹配.sh并打印
第四阶段:用 -exec 处理查找结果
题目 12:交互式删除 30 天前的临时文件
find /tmp -name "*.tmp" -mtime +30 -ok rm {} \;-ok 和 -exec
一样执行命令,但每个文件都会先问你确认。批量删除前先用
-ok,或者先不加删除动作 dry-run
跑一遍,是保命的好习惯。
题目 13:批量修改目录权限为 755
find /var/www/html -type d -exec chmod 755 {} \;{} 是查找到的文件的占位符,\;
表示命令结束。如果文件很多,用 + 代替
\; 可以把多个文件拼成一条命令执行,效率更高:
find /var/www/html -type d -exec chmod 755 {} +题目 14:复制小配置文件到备份目录
mkdir -p /backup/config
find . -name "*.conf" -size -10k -exec cp {} /backup/config/ \;注意提前建好目标目录,否则 cp 会报错。
综合实战:3 个完整脚本
前面都是单条命令,下面是 3 个真实运维/开发场景的完整脚本。需求来自实战,脚本逐行写好并加了注释,可以直接拿去用。
实战 1:定时日志清理与归档脚本
场景:服务器日志占满磁盘,需要定期归档旧日志并清理。
#!/bin/bash
#
# archive_old_logs.sh - 日志归档清理脚本
# 功能:查找指定目录下超过 7 天未修改的 .log 文件,
# 打包为 old_logs_<日期>.tar.gz 存到 /tmp/backup/,验证无误后删除原文件
# 用法:./archive_old_logs.sh /var/log/app
# 建议:配合 crontab 每天凌晨执行
# 0 2 * * * /path/to/archive_old_logs.sh /var/log/app >> /var/log/archive.log 2>&1
set -euo pipefail
# ---------- 1. 参数校验 ----------
LOG_DIR="${1:-}"
if [ -z "$LOG_DIR" ]; then
echo "用法: $0 <日志目录>"
echo "示例: $0 /var/log/app"
exit 1
fi
if [ ! -d "$LOG_DIR" ]; then
echo "错误: 目录 '$LOG_DIR' 不存在"
exit 1
fi
BACKUP_DIR="/tmp/backup"
DATE_STR=$(date +%Y%m%d)
ARCHIVE_PATH="${BACKUP_DIR}/old_logs_${DATE_STR}.tar.gz"
mkdir -p "$BACKUP_DIR"
# ---------- 2. 查找旧日志 ----------
echo "正在扫描 $LOG_DIR ..."
mapfile -t OLD_FILES < <(find "$LOG_DIR" -type f -name "*.log" -mtime +7 -print)
if [ ${#OLD_FILES[@]} -eq 0 ]; then
echo "没有发现超过 7 天未修改的 .log 文件,无需处理"
exit 0
fi
echo "发现 ${#OLD_FILES[@]} 个旧日志文件:"
printf ' %s\n' "${OLD_FILES[@]}"
# ---------- 3. 打包归档 ----------
echo "正在打包到 $ARCHIVE_PATH ..."
# -print0 + --null 可正确处理带空格/特殊字符的文件名
find "$LOG_DIR" -type f -name "*.log" -mtime +7 -print0 \
| tar --null -czf "$ARCHIVE_PATH" --files-from=- --no-recursion
if [ ! -s "$ARCHIVE_PATH" ]; then
echo "错误: 打包失败,保留原文件"
exit 1
fi
echo "打包成功: $ARCHIVE_PATH ($(du -h "$ARCHIVE_PATH" | cut -f1))"
# ---------- 4. 校验归档完整性,通过后再删除 ----------
echo "正在校验归档文件..."
if tar -tzf "$ARCHIVE_PATH" > /dev/null 2>&1; then
echo "校验通过,删除原文件..."
find "$LOG_DIR" -type f -name "*.log" -mtime +7 -delete
echo "清理完成,共删除 ${#OLD_FILES[@]} 个文件"
else
echo "错误: 归档文件损坏,保留原文件以防数据丢失"
exit 1
fi设计要点:
- 先打包、校验通过后再删除,任何一步失败都不会丢数据
- 用
-print0+tar --null处理文件名中的空格和特殊字符 set -euo pipefail让脚本遇到错误立即退出,避免误删文件
实战 2:代码库大文件与敏感信息排查脚本
场景:提交代码前,检查是否误带了大文件或私钥。
#!/bin/bash
#
# precommit_check.sh - 提交前检查脚本
# 功能:扫描项目目录(忽略 .git),找出大于 10MB 的文件和敏感私钥文件
# 用法:在项目根目录执行 ./precommit_check.sh [目录]
# 建议:做成 git pre-commit hook,提交时自动检查
set -euo pipefail
SCAN_DIR="${1:-.}"
SIZE_LIMIT_MB=10
FOUND_ISSUE=0
echo "正在扫描: $SCAN_DIR"
echo "======================================"
# ---------- 1. 大文件检查 ----------
echo "[1/2] 检查大文件 (>${SIZE_LIMIT_MB}MB)..."
mapfile -t BIG_FILES < <(find "$SCAN_DIR" -path "*/.git" -prune -o -type f -size +${SIZE_LIMIT_MB}M -print)
if [ ${#BIG_FILES[@]} -eq 0 ]; then
echo " ✓ 未发现大文件"
else
FOUND_ISSUE=1
echo " ⚠ 发现 ${#BIG_FILES[@]} 个大文件:"
for f in "${BIG_FILES[@]}"; do
SIZE_MB=$(du -m "$f" | cut -f1)
echo " ${SIZE_MB}MB $f"
done
fi
echo ""
# ---------- 2. 敏感文件检查 ----------
echo "[2/2] 检查敏感文件 (.key / .pem / id_rsa)..."
mapfile -t SENSITIVE < <(find "$SCAN_DIR" -path "*/.git" -prune -o -type f \
\( -name "*.key" -o -name "*.pem" -o -name "*id_rsa*" \) -print)
if [ ${#SENSITIVE[@]} -eq 0 ]; then
echo " ✓ 未发现敏感文件"
else
FOUND_ISSUE=1
echo " ⚠ 警告!发现 ${#SENSITIVE[@]} 个疑似敏感文件:"
printf ' %s\n' "${SENSITIVE[@]}"
echo " 请确认这些文件不在 git 追踪范围内!"
fi
echo "======================================"
if [ $FOUND_ISSUE -eq 0 ]; then
echo "检查通过,可以安全提交"
exit 0
else
echo "发现问题,请处理后再提交"
exit 1
fi设计要点:
- 用
-path "*/.git" -prune跳过 git 内部目录,避免误报 - 非零退出码可以直接接入 git hook,拦截问题提交
- 还可以扩展:检查
.env、*password*、*.p12等
实战 3:Web 目录权限批量安全修复脚本
场景:Web 服务器安全加固,规范文件/目录权限与所有者。
#!/bin/bash
#
# fix_web_perm.sh - Web 目录权限修复脚本
# 功能:目录设为 755,文件设为 644,所有者修正为 Web 用户
# 用法:sudo ./fix_web_perm.sh /var/www/wordpress [web_user]
set -euo pipefail
TARGET_DIR="${1:-}"
WEB_USER="${2:-www-data}"
# ---------- 1. 参数与环境检查 ----------
if [ -z "$TARGET_DIR" ]; then
echo "用法: $0 <目标目录> [Web用户]"
echo "示例: $0 /var/www/wordpress www-data"
exit 1
fi
if [ ! -d "$TARGET_DIR" ]; then
echo "错误: 目录 '$TARGET_DIR' 不存在"
exit 1
fi
if [ "$(id -u)" -ne 0 ]; then
echo "警告: 修改文件所有者需要 root 权限,建议用 sudo 运行"
fi
echo "目标目录: $TARGET_DIR"
echo "Web 用户: $WEB_USER"
echo "======================================"
# ---------- 2. 目录权限 755 ----------
echo "[1/3] 设置目录权限为 755..."
DIR_COUNT=$(find "$TARGET_DIR" -type d | wc -l)
find "$TARGET_DIR" -type d -exec chmod 755 {} +
echo " 已处理 $DIR_COUNT 个目录"
# ---------- 3. 文件权限 644 ----------
echo "[2/3] 设置文件权限为 644..."
FILE_COUNT=$(find "$TARGET_DIR" -type f | wc -l)
find "$TARGET_DIR" -type f -exec chmod 644 {} +
echo " 已处理 $FILE_COUNT 个文件"
# ---------- 4. 修正所有者 ----------
echo "[3/3] 修正所有者为 ${WEB_USER}:${WEB_USER}..."
if id "$WEB_USER" &>/dev/null; then
WRONG_COUNT=$(find "$TARGET_DIR" ! -user "$WEB_USER" | wc -l)
if [ "$WRONG_COUNT" -gt 0 ]; then
find "$TARGET_DIR" ! -user "$WEB_USER" -exec chown "${WEB_USER}:${WEB_USER}" {} +
echo " 已修正 $WRONG_COUNT 个文件的所有者"
else
echo " 所有者均正确,无需修改"
fi
else
echo " 警告: 用户 '$WEB_USER' 不存在,跳过所有者修正"
fi
echo "======================================"
echo "权限修复完成"设计要点:
- 用
{} +代替{} \;,把多个文件合并为少量 chmod/chown 调用,大目录下快得多 ! -user只处理所有者不对的文件,避免无意义的 chown- 注意:644/755 是通用安全基线,上传目录等特殊场景可能需要微调
练习建议
- 先抄后改:把上面的命令在
~/find_test里亲手跑一遍,观察输出 - 故意犯错:试试去掉
-print、写错-mtime的正负号,看看会发生什么——犯错是最好的老师 - 改造脚本:把实战 1 的 7 天改成 30 天,把实战 2 接入你项目的 pre-commit hook
- 查手册:
man find是终极文档,重点看-perm的三种写法和-exec的+vs\;
find
的强大在于组合:条件是”筛子”,-exec
是”手”。筛子越细、手越稳,你在 Linux 下就越游刃有余。
| 本文由 BOSH 的博客助手 HerMes 整理 🔍 |