Linux find 命令从入门到实战:循序渐进训练计划
title: Linux find 命令从入门到实战:循序渐进训练计划
slug: 1790409995201
date: 2026-09-26
summary: 从按名称查找到定时日志归档脚本,一份循序渐进的 find 命令训练计划,附 3 个可直接使用的完整运维脚本。
tags:
find 是 Linux 下最强大的文件查找工具之一,但它的参数多、组合灵活,很多初学者望而却步。这篇文章给你一份循序渐进的训练计划:从基础查找到 3 个真实运维场景的完整脚本,跟着练一遍,find 就真正变成你的肌肉记忆了。
准备工作:搭建练习环境
动手之前,先创建一个测试目录,造一些文件用来练手:
1 2 3 4 5
| 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 结尾的文件:
如果想不区分大小写(比如同时匹配 .LOG),用 -iname:
题目 2:只查找目录
-type 是最常用的过滤条件之一:f 表示普通文件,d 表示目录,l 表示符号链接。
题目 3:查找隐藏文件
Linux 下以 . 开头的是隐藏文件:
第二阶段:按大小与时间查找
题目 4:查找大于 10MB 的文件
-size 的单位很有讲究:+10M 表示大于 10MB,-10M 表示小于 10MB,10M 表示约等于。单位还可以用 k(KB)、G(GB)、c(字节)。
题目 5:查找 24 小时内修改过的文件
1 2 3
| find . -mtime -1
find . -mmin -1440
|
-mtime -1 表示修改时间在 1 天以内,-mmin -1440 是同样的意思(24×60=1440 分钟)。
题目 6:查找 7 天前被访问过的文件
注意这里是 +7(7 天以前),不是 -7。atime 是访问时间,mtime 是修改时间,ctime 是状态改变时间——三者的区别是面试常客,值得记住。
第三阶段:深度、权限与逻辑组合
题目 7:限制查找深度
只在当前目录下找 .txt 文件,最多深入两层子目录:
1
| find . -maxdepth 2 -name "*.txt"
|
-maxdepth 建议放在其他条件前面,否则在某些 find 实现里会给出警告。
题目 8:在 /var/log 下不区分大小写找日志
1
| find /var/log -iname "*.log"
|
题目 9:按权限查找
查找权限为 777 的文件(安全排查常用):
1
| sudo find /var -perm 777 -ls
|
-perm 777 是精确匹配;-perm -777 表示"至少包含"这些权限位;-perm /777 表示"包含其中任意"。排查可疑文件时 -perm -4000(找 SUID 文件)也很常用。
题目 10:逻辑或组合
查找 .jpg 或 .png 图片:
1
| find /data \( -name "*.jpg" -o -name "*.png" \)
|
括号需要转义(或加引号),否则 shell 会误解。-o 是 OR,-a 是 AND(默认可省略),! 是 NOT。
题目 11:排除 .git 目录
查找所有 .sh 脚本,但跳过 .git:
1
| find . -path "*/.git" -prune -o -name "*.sh" -print
|
这行值得拆开理解,它本质是个 if-else:
-path "*/.git":当前路径是不是 .git 目录?
-prune:如果是,直接剪掉这根"树枝",不往下递归
-o:否则,执行后面的逻辑
-name "*.sh" -print:匹配 .sh 并打印
第四阶段:用 -exec 处理查找结果
题目 12:交互式删除 30 天前的临时文件
1
| find /tmp -name "*.tmp" -mtime +30 -ok rm {} \;
|
-ok 和 -exec 一样执行命令,但每个文件都会先问你确认。批量删除前先用 -ok,或者先不加删除动作 dry-run 跑一遍,是保命的好习惯。
题目 13:批量修改目录权限为 755
1
| find /var/www/html -type d -exec chmod 755 {} \;
|
{} 是查找到的文件的占位符,\; 表示命令结束。如果文件很多,用 + 代替 \; 可以把多个文件拼成一条命令执行,效率更高:
1
| find /var/www/html -type d -exec chmod 755 {} +
|
题目 14:复制小配置文件到备份目录
1 2
| mkdir -p /backup/config find . -name "*.conf" -size -10k -exec cp {} /backup/config/ \;
|
注意提前建好目标目录,否则 cp 会报错。
综合实战:3 个完整脚本
前面都是单条命令,下面是 3 个真实运维/开发场景的完整脚本。需求来自实战,脚本逐行写好并加了注释,可以直接拿去用。
实战 1:定时日志清理与归档脚本
场景:服务器日志占满磁盘,需要定期归档旧日志并清理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| #!/bin/bash
set -euo pipefail
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"
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[@]}"
echo "正在打包到 $ARCHIVE_PATH ..."
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))"
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:代码库大文件与敏感信息排查脚本
场景:提交代码前,检查是否误带了大文件或私钥。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| #!/bin/bash
set -euo pipefail
SCAN_DIR="${1:-.}" SIZE_LIMIT_MB=10 FOUND_ISSUE=0
echo "正在扫描: $SCAN_DIR" echo "======================================"
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 ""
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 服务器安全加固,规范文件/目录权限与所有者。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| #!/bin/bash
set -euo pipefail
TARGET_DIR="${1:-}" WEB_USER="${2:-www-data}"
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 "======================================"
echo "[1/3] 设置目录权限为 755..." DIR_COUNT=$(find "$TARGET_DIR" -type d | wc -l) find "$TARGET_DIR" -type d -exec chmod 755 {} + echo " 已处理 $DIR_COUNT 个目录"
echo "[2/3] 设置文件权限为 644..." FILE_COUNT=$(find "$TARGET_DIR" -type f | wc -l) find "$TARGET_DIR" -type f -exec chmod 644 {} + echo " 已处理 $FILE_COUNT 个文件"
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 整理 🔍