1. 为什么需要计算文件总大小?
在日常Linux系统管理中,计算一组文件的总大小是个高频需求场景。想象你正在清理服务器磁盘空间,需要评估某个日志目录下所有.gz压缩包的总大小;或者作为开发者,你想知道项目node_modules目录到底占用了多少空间;又或者作为运维人员,需要统计某个用户家目录下所有视频文件的总存储量。这些场景下,单纯用ls -lh逐个查看文件大小再手动相加显然效率低下。
Linux系统自带的du(disk usage)命令就是为这类需求而生的利器。与ls命令显示的文件逻辑大小不同,du统计的是文件实际占用的磁盘块大小,这对存储空间管理更具参考价值。例如一个1字节的文件实际会占用4KB的磁盘块(取决于文件系统块大小),ls显示1B而du显示4K。
关键区别:
ls -l显示文件的逻辑大小(内容实际字节数),而du显示物理占用空间(考虑磁盘块分配的最小单位)。当文件数量多或存在大量小文件时,两者统计结果可能差异显著。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 基础命令解析:du的核心用法
2.1 基本语法与常用参数
du命令的标准调用格式为:
bash复制du [选项] [文件或目录...]
最实用的参数组合是-sh:
-s(--summarize):只显示总计大小,不递归列出子目录-h(--human-readable):以K/M/G等易读单位自动转换大小
例如计算当前目录总大小:
bash复制du -sh .
输出类似:
code复制4.8G .
若需统计多个指定文件/目录,直接并列路径参数:
bash复制du -sh /var/log/*.log
这将输出每个.log文件的大小,但不会自动求和。要获得总和,需要借助其他命令组合(见第3章)。
2.2 进阶实用参数
--apparent-size:显示逻辑大小(类似ls),而非磁盘占用-b/-k/-m/-B:强制以Bytes/KB/MB/指定块数为单位输出--time:显示最后修改时间--exclude="PATTERN":排除匹配模式的文件-c:在最后一行显示总计(需与-s配合使用)
示例:统计/home下除.mp4文件外的总大小
bash复制du -sh --exclude="*.mp4" /home
3. 多文件统计:三种求和方法论
3.1 方法一:管道配合awk求和
当du输出多行结果时,用awk累加第二列数值:
bash复制du -sk /var/log/* | awk '{sum+=$1} END {print sum}'
输出纯数字结果(单位为KB)。如需人性化显示:
bash复制du -sk /var/log/* | awk '{sum+=$1} END {print sum/1024 "MB"}'
实测技巧:如果路径包含空格,需先设置
IFS环境变量:bash复制(IFS=$'\n'; du -sk /var/log/* | awk '{sum+=$1} END {print sum}')
3.2 方法二:find+xargs组合拳
对于分散在不同目录的文件,先用find定位再统计:
bash复制find /project -name "*.js" -type f -print0 | xargs -0 du -ch | tail -1
关键点:
-print0和-0处理含空格路径-c使du输出总计行tail -1提取最后的总计结果
3.3 方法三:数组遍历(Bash脚本)
在脚本中可先将文件存入数组再遍历计算:
bash复制files=(/path/to/files/*)
total=0
for f in "${files[@]}"; do
size=$(du -sk "$f" | cut -f1)
total=$((total + size))
done
echo "Total size: $((total/1024))MB"
性能对比:
| 方法 | 适用场景 | 执行速度 | 内存占用 |
|---|---|---|---|
| awk管道 | 文件数量少(<1000) | 快 | 低 |
| find+xargs | 深层目录/复杂过滤条件 | 中 | 中 |
| 数组遍历 | 需要后续处理单个文件大小 | 慢 | 高 |
4. 实战陷阱与避坑指南
4.1 权限不足导致的统计偏差
当部分子目录无读取权限时,du会输出"Permission denied"警告且不统计这些目录。这会导致结果小于实际占用空间。两种解决方案:
- 使用sudo提升权限(可能带来安全风险):
bash复制sudo du -sh /var/*
- 通过
2>/dev/null忽略错误(结果仍不准确):
bash复制du -sh /var/* 2>/dev/null
更安全的做法是先用find过滤可读目录:
bash复制find /var -type d -readable -exec du -sh {} +
4.2 符号链接引发的重复计算
默认情况下,du会跟踪符号链接统计实际文件大小。这可能导致:
- 循环引用引发无限递归
- 同一文件被多次统计
使用-P选项禁止跟踪符号链接:
bash复制du -Psh /path/with/links
或者用-L强制统计链接目标大小(慎用):
bash复制du -Lsh /path/with/links
4.3 稀疏文件的特殊处理
稀疏文件(如虚拟机磁盘镜像)可能有"逻辑大小 ≠ 物理占用"的特性。例如:
code复制$ ls -lh sparse.img
-rw-r--r-- 1 user user 100G Jun 1 10:00 sparse.img
$ du -h sparse.img
2.1G sparse.img
此时--apparent-size参数就很有用:
bash复制du --apparent-size -sh sparse.img
5. 高阶应用场景
5.1 按大小排序文件
组合sort命令实现按大小降序排列:
bash复制du -sh /var/log/* | sort -rh
关键参数:
-r:逆序排列-h:识别人类可读大小(K/M/G)
5.2 定时监控目录增长
创建每日增长量监控脚本(保存为monitor_dir.sh):
bash复制#!/bin/bash
target_dir="/var/log"
log_file="/tmp/dir_size.log"
current_size=$(du -sm "$target_dir" | cut -f1)
date_stamp=$(date "+%Y-%m-%d %H:%M:%S")
echo "$date_stamp,$current_size" >> "$log_file"
然后添加cron任务(每天0点执行):
bash复制0 0 * * * /path/to/monitor_dir.sh
5.3 图形化显示磁盘使用
安装ncdu工具进行交互式分析:
bash复制sudo apt install ncdu # Debian/Ubuntu
ncdu /path/to/scan
典型输出:
code复制--- /var/log ---
4.8GiB [##########] /apache2
1.2GiB [## ] /nginx
800.3MiB [# ] /audit
6. 性能优化技巧
6.1 加速大目录统计
对于包含数百万文件的目录(如邮件服务器),常规du可能极慢。解决方案:
- 使用
--files0-from从文件列表读取(避免shell扩展):
bash复制find /data -type f -print0 | du --files0-from=- -ch | tail -1
- 采用更快的
dust工具(Rust编写):
bash复制cargo install du-dust
dust /large_dir
6.2 跳过特定文件系统
避免统计挂载的NFS/远程存储:
bash复制du -shx / # -x保持在同一文件系统
6.3 并行处理加速
使用GNU parallel工具并行计算:
bash复制find /data -type d | parallel -j 8 du -s {}
我在处理一个包含120万文件的备份目录时,上述方法将统计时间从18分钟缩短至2分钟。注意线程数(-j)应根据CPU核心数调整,通常设为核心数的1.5-2倍。
