首页 > Sysadmin > 正文

Linux 查找大文件并清理:先定位再动手

huyuanwen 2026-10-28 Sysadmin

磁盘空间告急别急着 rm。先用 du 和 find 定位,再用 lsof 查”删了没释放”,最后按类型动手,关键命令均在 WSL 实测。

一、先分清口径:du 数磁盘占用,find 数文件字节

清理前的第一个决定就有人做错:du 报的是文件**占用的磁盘块**,find -size 用的是 st_size,也就是 ls -l 那种**文件字节数** [1],两者对稀疏文件会完全对不上。在测试目录里造了四种文件后实测:

| 文件 | 造法 | du -sh | find -size +100M | | — | — | — | — | | alloc.bin | fallocate 300M | 301M | 命中(314572800) | | sparse.bin | truncate 500M | **0** | **命中**(524288000,排第 1) | | real.bin | dd 写 200M | 200M | 命中(209715200) | | mid.bin | 写入 1.5M | 1.5M | 不命中 |

所以按”谁真的吃磁盘”清理要看 du,按”文件名义大小”排查(比如传输、配额)才看 find。日常定位大目录:

du -xh --max-depth=1 / 2>/dev/null | sort -rh | head   # -x 不跨挂载点,逐个目录下钻
du -sh ./* 2>/dev/null | sort -rh | head               # 当前目录下逐项排序

排序靠 GNU sort 的 -h;busybox 等精简系统没有这个参数,可退回 du -k 再 sort -rn(此为文档口径,精简系统未实测)。

二、find 定位大文件:取整规则和 -t 的坑

find / -xdev -type f -size +100M -printf '%s\t%p\n' | sort -rn | head -20
find /var -type f -name '*.log' -mtime +30 -size +10M   # 只要 30 天没改过的大日志
du -ah -t 250M /var 2>/dev/null | sort -rh | head       # du 版:≥250M 才显示

三个实测确认的细节:

  • **-size 是向上取整后比较**:1.5M 的文件命中 +1M、不命中 +2M;手册原话是 -size -1M 只匹配空文件,实测结果一致(所有命中项都是 0 字节)[1]。
  • **printf 的 %s 输出字节数**,接 sort -rn 就是现成的”大文件排行榜”;%TY-%Tm-%Td 才能打印日期,%m、%d 会打印成权限位。
  • **du -t 想筛文件必须加 -a**:只写 du -t 250M –max-depth=1 时实测整个测试目录只输出了总数一行,所有文件都不显示——因为 du 默认只统计目录,正数阈值是把小于它的条目藏起来 [2]。
  • 三、确认之后再删:-delete 的安全用法

    手册建议的稳妥流程是:同样的条件先跑 -print,人工核对一遍,再把 -print 换成 -delete [1]。

    find /var/cache/app -type f -mtime +30 -name '*.tmp' -print   # 第一步:只看,不删
    find /var/cache/app -type f -mtime +30 -name '*.tmp' -delete  # 第二步:删除,文件消失,退出码 0
    find /var/cache/app -depth -type d -empty -delete             # 第三步:清空的目录再来一遍

    实测确认三点:-delete 隐含 -depth,目录**只有为空时**才会被删,非空目录会留在原地;手册同时警告它和 -prune 的组合会有不可预料的后果,不要搭配使用。两句均为 find 手册口径 [1]。

    四、明明删了大文件,df 却纹丝不动

    这是”清理无效”的头号原因:文件已删,但还有进程握着它的文件描述符,POSIX 要等最后一个 fd 关闭才真正释放空间。实测:300M 文件被 sleep 进程打开后 rm,df 空闲量分毫未动;lsof 立刻抓到它:

    lsof +L1                       # NLINK 列为 0、路径带 (deleted) 的就是元凶
    ls -l /proc/<pid>/fd           # 备选:从进程侧看它握着的已删文件
    systemctl restart <服务名>     # 让持有它的服务重开文件,空间当场归还

    实测数据:300M 文件 rm 后 df 空闲量不变,lsof +L1 显示 sleep 进程 3 号 fd 持有该文件(NLINK 0,SIZE/OFF 314572800);杀掉持有进程后 df 空闲量恢复原值。+L1 的语义就是”挑出已被 unlink 的打开文件” [3]。

    五、正在写的日志:用 truncate 清零,别直接 rm

    对活跃日志直接 rm,实测后果就是上一节:150M 日志删掉后 df 不降,直到写日志的进程退出才归还。正确姿势是保留 inode、把内容截断:

    truncate -s 0 /var/log/app/access.log   # 文件在、fd 在、空间立刻回
    journalctl --disk-usage                 # 看 journal 总量(实测输出 808.0M)
    journalctl --vacuum-size=200M           # 按手册口径清理,本机未实际执行

    truncate -s 0 实测:200M 日志清零后 df 空闲量立即 +200M,写进程毫无察觉。journal 方面,手册提醒 –vacuum-size 只删**已归档**的 journal 文件,–disk-usage 还包含活动文件,所以跑完 vacuum 数字不一定同步下降 [6]。

    六、想要可视化:ncdu

    ncdu 是 ncurses 界面的磁盘占用浏览器,官方定位就是”在没图形界面的机器上快速找出吃了多少空间” [4]。Ubuntu 24.04 里 apt 可直装(实测装到 1.19-0.1),Debian trixie 的包已到 1.22-1 [5]。实测确认它的无终端导出模式可用:ncdu -x -o out.json /root/bigT 退出码 0,JSON 里每个条目同时带 asize(名义大小)和 dsize(磁盘占用),正好对应第一节的两个口径。交互式界面的操作手感非终端环境无法实测,未验证。

    | 现象 | 原因 | 处理 | | — | — | — | | du 扫遍全盘找不到大块头,df 却见少 | 已删除未释放 | lsof +L1 找持有进程,重启服务 | | find -size 命中,du -sh 却是 0 | 稀疏文件,口径不同 | 对比 du –apparent-size 再决定删不删 | | -delete 跑完空目录还在 | 目录非空时不删 | 补一遍 -depth -type d -empty -delete | | du -t 250M 什么都没输出 | 默认只统计目录 | 加 -a 看文件级 | | sort: invalid option — ‘h’ | 非 GNU sort | du -k 配 sort -rn |

    **常见问题**

  • 问:du 和 find 报的大小差很多,信哪个? 答:信 du 判断磁盘占用,信 find 判断文件名义大小;稀疏文件二者本来就该不同,不是谁坏了 [2]。
  • 问:-size +1M 和 -size +1048576c 一样吗? 答:不一样,手册明确 -1M 只匹配空文件而 -1048576c 匹配 0 到 1048575 字节,取整规则见 find 手册 [1]。
  • 问:清理前想再稳一点? 答:先用 -print 出清单存文件,确认后再换 -delete;重要目录先 cp -a 或打包备份再动手。
  • 问:ncdu 会不会很吃资源? 答:首次扫描大分区需要时间,之后可在缓存文件间切换浏览(官方页描述,未实测)。
  • 局限性:本文测试环境为 WSL2 Ubuntu 24.04(findutils 4.9.0、coreutils 9.4、lsof 4.95、ncdu 1.19,测试日期 2026-10-27),单 ext4 文件系统;systemd journal 的 vacuum 仅做了 –disk-usage 实测,删除动作基于手册未执行;RPM 系发行版、SELinux 环境及真实生产磁盘未覆盖;sort -h 缺失行为、ncdu 交互界面均为文档口径。

    **实测记录**

  • 环境:WSL2 Ubuntu 24.04.4 LTS,内核 6.6.114.1,root;GNU findutils 4.9.0、GNU coreutils 9.4、lsof 4.95.0、ncdu 1.19-0.1。日期:2026-10-27。
  • du 排序:alloc.bin 301M > real.bin 200M > cache 151M;稀疏文件 du 报 0、–apparent-size 报 500M。
  • find 取整:1.5M 文件命中 +1M、不中 +2M;-size -1M 命中项全部为 0 字节;-size +100M 按 -printf %s 排序,500M 稀疏文件排首位。
  • -delete:删文件 rc=0;空目录经 -depth -type d -empty -delete 删除,非空目录保留。
  • 已删未释放:建 300M 文件后 df 空闲 969242M,rm 后仍是 969242M(未回升),lsof +L1 可见 NLINK 0;杀持有进程后回到建文件前的 969542M。
  • truncate:写进程持有 fd 的 200M 日志 -s 0 清零,df 空闲量 969342M→969542M;对照组 rm 150M 日志,退出持有进程后才回升。
  • journalctl –disk-usage 输出 808.0M;ncdu 导出 JSON 模式 rc=0,包已 purge 清理。

  • 参考资料

    文中主要命令已在 WSL Ubuntu(24.04)实测并核对其在 Debian 系与通用发行版的文档口径。