拿到一张FAT格式的磁盘镜像,想看看里面到底装了哪些东西、占了多少空间,又不想为了这么点事就去挂载、要root权限、还得记一堆挂载参数——这时候mdu就是那个能帮你省事的命令。它是mtools工具包里专门负责统计MS-DOS文件系统目录占用空间的成员,我最早是在维护一批软盘镜像和嵌入式启动盘时接触到它的,用顺手之后发现,凡是跟FAT镜像打交道的工作流里,它都能派上用场。
这篇东西适合两类人看:一类是正在做Linux运维、经常捣鼓分区镜像和启动盘的老手,想知道除了du之外还有什么更贴合的磁盘占用统计手段;另一类是刚接触Linux命令、看到“命令大全”系列准备逐个上手练的新手,需要一个能零基础跟着敲的实操入口。我会从mdu的定位开始讲,接着把安装、镜像准备、参数拆解、实战案例、踩坑排错一条龙走完,保证你读完就能直接用。
1. mdu命令的定位:为什么磁盘管理会用到这个冷门命令
1.1 先分清mdu和du:一个管FAT,一个管Linux原生文件系统
很多人在网上搜“磁盘管理命令”时,第一眼看到mdu会下意识觉得这是du的某个变体。实际上两者操作的对象完全不同。du是用来统计Linux原生文件系统(ext4、xfs、btrfs这些)上目录和文件的磁盘占用,它的统计口径是“当前挂载点所在文件系统上,这个目录树实际消耗了多少块”。mdu则是mtools工具包里的一个命令,专门用来直接读MS-DOS文件系统(也就是FAT12/FAT16/FAT32)上的目录占用,它不需要把文件系统挂载到Linux目录树里,而是直接以文件或设备作为操作对象。
这个区别非常关键。比如说你有一个从老设备里导出的.img磁盘镜像,里面是FAT32分区,你直接用du去统计它毫无意义——du只能看到这个镜像文件本身在宿主机上占了多大,看不到镜像内部的文件结构。而mdu可以钻进这个镜像内部,像在DOS系统里执行dir一样,把目录树的实际占用报出来。
我印象最深的一次使用场景是在做老式工控机的系统备份时,客户丢过来一个256MB的CF卡镜像,让我确认里面的固件目录是不是快占满整个分区了。当时我第一反应是mount -o loop挂载,结果那台机器的内核没开loop设备支持,折腾半天。后来换用mdu,一条命令就拿到了目录占用,连镜像文件都只读不写,安全得多。
1.2 mdu必须配合mtools使用,理解这套工具链的定位
mdu不是一个孤立命令,它是mtools这个“MS-DOS工具集”里的一员。mtools里还有mcopy、mdir、mdel、mformat、mtype等一堆命令,组合起来可以让你完全不依赖mount就能完成对FAT文件系统的读写、查看、格式化等操作。这个工具包的设计初衷是让Unix/Linux用户能方便地访问DOS格式的磁盘,最早可以追溯到上世纪80年代末,生命力相当顽强。
理解这套工具链的定位很重要。它就相当于在Linux和FAT文件系统之间架了一座“翻译桥”:你通过mcopy把文件拷进镜像,通过mdir查看镜像里的文件列表,通过mdu检查目录占用。所有操作都直接作用于镜像文件或块设备上,不需要内核文件系统驱动的参与,所以即使你手上是一个没有root权限的账号,只要对镜像文件有读权限,就能用mdu完成空间统计。
mdu在整个工具链里的角色就是“空间检查员”。它和mcopy、mformat是黄金搭档:mformat格式化出一个FAT文件系统后,mcopy往里传文件,传完之后用mdu看看占了多少、还剩多少,不用来回挂载卸载。这套流程在自动化脚本里尤其好用,后面实操章节我会完整演示。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 装好mtools并准备好测试镜像
2.1 不同发行版安装mtools的命令
大多数Linux发行版的软件源里都带mtools,安装非常简单。Debian/Ubuntu系用apt,CentOS/RHEL系用yum/dnf,Arch系用pacman:
bash复制# Debian / Ubuntu
sudo apt install mtools
# CentOS / RHEL / Rocky / AlmaLinux,8以上用dnf
sudo yum install mtools
# 或
sudo dnf install mtools
# Arch / Manjaro
sudo pacman -S mtools
装完之后可以直接敲mdu --version验证一下,能输出版本号说明安装成功。这里有个小习惯我建议新手养成:每次装完一个命令,先用man mdu把文档翻一遍,不用全看,先扫一眼参数列表,知道这命令有哪些能力。等真正遇到问题再回来精读对应段落,效率最高。
2.2 制作一个用于练习的FAT镜像
要实操mdu,你需要一个FAT文件系统镜像。最快的办法是直接用dd创建一个空白镜像文件,然后用mkfs.vfat格式化。mkfs.vfat在Linux下属于dosfstools包,如果提示没有这个命令,先装一下:
bash复制# 创建64MB的空镜像
dd if=/dev/zero of=/tmp/test.img bs=1M count=64
# 格式化成FAT32
mkfs.vfat -F 32 /tmp/test.img
如果没有mkfs.vfat,Debian/Ubuntu系执行sudo apt install dosfstools,CentOS系执行sudo yum install dosfstools。
接下来用mtools往镜像里放一些文件。这里先介绍两种访问方式,一种是直接用-i参数指定镜像文件,一种是通过配置文件映射盘符。我推荐先用-i,简单直接,不污染全局配置:
bash复制# 在镜像根目录下创建firmware目录
mmd -i /tmp/test.img ::/firmware
# 往firmware目录里拷两个文件
mcopy -i /tmp/test.img /etc/hostname ::/firmware/
mcopy -i /tmp/test.img /etc/hosts ::/firmware/
# 再在根目录放一个文件
mcopy -i /tmp/test.img /etc/fstab ::/
这里::/表示镜像内部的根目录,两个冒号是mtools中“当前驱动器根目录”的标准写法。mcopy的用法跟cp很像,只是需要在目标路径前加上镜像标识。
2.3 用mtools配置文件管理多个镜像
如果你经常跟多个镜像打交道,每次都在命令后面带-i /path/to/image.img会显得很啰嗦。mtools支持通过配置文件把某个盘符映射到镜像文件上。全局配置文件是/etc/mtools.conf,用户级配置文件是~/.mtoolsrc。
假设我想把m:这个盘符固定指向这个测试镜像,可以编辑~/.mtoolsrc写入:
code复制drive m: file="/tmp/test.img"
保存后,前面那些命令就能简写为:
bash复制mmd m:/
mcopy /etc/hostname m:/firmware/
mdu m:/
这里有个日常用得上的经验:如果你在做很多个独立项目的镜像,建议每个项目一个独立盘符,比如p:指向projectA.img,q:指向projectB.img。配置文件里放满注释,写明每个盘符对应哪个项目,一个月后你回来接着用,一看注释就知道哪个是哪个,不会搞混。
3. mdu三个核心参数的使用拆解
3.1 不带参数:查看目录总占用
mdu最基础的用法就是直接指定要统计的目录。接着上面的测试镜像,执行:
bash复制mdu -i /tmp/test.img ::/firmware
输出结果类似:
code复制6 ::/firmware
这个数字表示firmware目录在FAT文件系统里实际占用了6KB。你现在可能有个疑问:里面存了hostname和hosts两个文件,加起来不到1KB,为什么mdu报出6KB?
这就得说到FAT文件系统的空间分配方式了。FAT文件系统以簇(cluster)为最小分配单位,一个文件即使只有1字节,也要占用整个簇。这个测试镜像用mkfs.vfat -F 32格式化时,默认簇大小是4KB。hostname和hosts分别占用一个簇,加起来是8KB才对,但mdu统计的是目录本身和其下所有文件——目录表项还要额外占用空间,而这个镜像里FAT表项的分配粒度可能让最终结果呈现出6KB这个数值。
实际上,mtools统计的是“文件实际占用的簇数乘以簇大小再除以1024”的结果,目录本身的目录项(directory entry)也会占据一定的空间。如果你用du -b去看FAT分区中文件的逻辑大小,和mdu的统计会有明显差异——这正是mdu的价值所在:它报告的是“在这个文件系统里真实占用的空间”,而不是“文件内容的逻辑大小”。对于需要精确判断磁盘是否够用的场景,这个数字比文件逻辑大小的累加更有参考意义。
3.2 -a参数:逐文件列出占用明细
mdu加上-a参数后,会递归列出目录下所有文件和子目录的占用情况,输出格式是“大小 路径”:
bash复制mdu -a -i /tmp/test.img ::/firmware
输出类似:
code复制3 ::/firmware/hostname
3 ::/firmware/hosts
6 ::/firmware
注意看,每个文件单独显示的是3KB而不是4KB。这里其实是mtools的显示精度问题:文件实际占用了4KB即4096字节,但mdu以KB为单位显示时做了某种取整或进制换算,导致你看到的数值和理论值有偏差。真正精确到字节级需要看簇大小和文件占用的簇数量。
这个现象在mdu里很常见,尤其是在FAT32格式下,默认簇大小4KB时,小文件的显示值会显得很“碎”。我建议在看明细时别纠结单位微小的出入,关注数量级和整体趋势即可。如果你需要精确到字节的空间报告,mdu不是最合适的工具,之后可以用mount -o loop挂载后再用du --block-size=1来核对。
3.3 -s参数:只输出合计值,适合写脚本
-s是“summarize”的简写,只输出总计,不列明细。在统计一个包含大量子目录的镜像时,这能让输出干净不少:
bash复制mdu -s -i /tmp/test.img ::/
输出:
code复制9 ::/
对比一下:firmware目录6KB,根目录下的fstab文件3KB(实际4KB簇),合计9KB。根目录本身的目录表项是在FAT32格式化时预分配的,不一定计入mdu的统计范围,所以这个数字基本合理。
-s参数在脚本里非常有用。比如你想遍历多个镜像并汇总它们的空间占用,就可以在shell循环里用mdu -s拿数字,再用awk提取第一列做累加。需要注意mdu默认单位是KB,如果你的统计口径需要MB或者块数,需要自己做换算。
4. 实操:用mdu预检U盘启动镜像的空间占用
4.1 场景设定:往镜像里灌文件,检查是否超容量
在生产环境中,我经常需要定制一些启动镜像——比如给特定硬件平台做维护U盘,需要把内核、initramfs、应用脚本、配置文件打包进一个FAT分区镜像里,最后再用dd写入物理U盘。这个过程最怕的就是:文件全放进去了,结果超过目标U盘容量,或者超过了FAT分区的最大容量,导致镜像“超载”,一启动就出问题。
用mdu做预检是我推荐的方案。流程分三步:先格式化一个和目标U盘容量一致的镜像文件,然后通过mcopy把需要的文件全部传进去,最后用mdu统计镜像内部总占用,确认不超过容量阈值。整个过程不需要mount,不需要root,纯用户态操作,跑在CI流水线里也没问题。
4.2 完整命令流程
假设我要做一个128MB的维护启动镜像,需要放入以下内容:
- vmlinuz内核文件,约8MB
- initrd.img,约32MB
- scripts目录,包含若干脚本文件,共约20MB
- tools目录,共约10MB
目标U盘容量128MB。FAT32格式化后,正常情况下用户可用的空间约127MB左右(文件系统元数据会占一点)。我的判断阈值是:镜像内文件总占用不得超过120MB,留出余量给后续可能追加的配置文件。
操作命令如下:
bash复制# 1. 创建128MB镜像
dd if=/dev/zero of=/tmp/boot.img bs=1M count=128
# 2. 格式化为FAT32(默认簇大小4KB)
mkfs.vfat -F 32 /tmp/boot.img
# 3. 划一个盘符映射,方便后续操作
echo 'drive b: file="/tmp/boot.img"' >> ~/.mtoolsrc
# 4. 建立目录结构
mmd b:/scripts
mmd b:/tools
# 5. 拷贝文件
mcopy /some/path/vmlinuz b:/
mcopy /some/path/initrd.img b:/
mcopy -r /some/path/scripts/* b:/scripts/
mcopy -r /some/path/tools/* b:/tools/
# 6. 用mdu检查总占用
mdu -s b:/
如果输出是120640 b:/,将近118MB,还在安全线以内,这个镜像可以继续用。如果输出超过了125000,说明空间非常紧张,我就要考虑精简掉一些不必要的文件,或者改用簇大小更小的FAT16来减少空间浪费。
4.3 怎么看懂输出并判断余量
mdu输出的是KB。对一个128MB镜像来说,总共约131072KB。mdu -s显示的是用户文件占用的空间,由于FAT文件系统的元数据(FAT表、根目录区等)占据少量空间,可用的用户空间可能只有130000KB左右。所以判断余量时不能直接用131072去减,要留出2-3MB的元数据和尾部空间余量。
实际项目里我一般这样计算:
- 查看镜像扇区总数:
fdisk -l /tmp/boot.img,或用mdu之外的工具,比如fsck.fat -v /tmp/boot.img。 - 用mdu拿到用户文件占用。
- 估算可用余量 = 分区总用户空间 - mdu的结果。
如果余量小于总容量的5%,我会认为这个镜像太“满”,不建议直接烧录。FAT文件系统在接近满的时候,文件碎片会显著增加,读写性能下降,而且某些老设备固件对接近满的FAT分区兼容性也不好。保持至少10%的空闲是我自己定的安全线。
4.4 组合脚本:批量预检多个镜像
如果你跟我一样要同时处理好几个架构的启动镜像,可以写个简单循环把mdu结果全部汇总出来:
bash复制for img in /tmp/*.img; do
size=$(mdu -s -i "$img" ::/ 2>/dev/null | awk '{print $1}')
echo "$img : ${size} KB"
done
这里2>/dev/null是把mdu对非FAT镜像的报错信息吞掉,避免脚本被错误刷屏。如果你希望报错时能看到原因,可以直接去掉这个重定向,逐个排查。
5. mdu使用中的坑与排错思路
5.1 mdu和du结果不一致:不是命令出bug,是文件系统不同
有次我在项目群里看到有人说“mdu统计的怎么跟du差这么多,是不是命令有问题”。这其实是把两者统计范围搞混了。当你对镜像文件本身执行du -h /tmp/test.img时,得到的是这个镜像文件在宿主机ext4文件系统上占用的物理块大小——对于dd创建的全零镜像,ext4可能会做稀疏文件优化,显示出来的“占用”甚至比镜像逻辑大小还小;而mdu显示的是镜像内部FAT文件系统里文件占用的真实空间。两者口径完全不同,不能直接对比。
如果你挂载了镜像,在挂载目录里执行du,又会出现另一种差异:du默认统计的是文件逻辑大小乘以块数,计算的是Linux VFS层看到的占用,而FAT的簇分配机制会导致“逻辑大小总和”和“实际占用的簇空间总和”不一致。mdu的优势就是它直接从FAT表出发,统计的是“在这个文件系统上真实被占用的簇空间”。所以遇到mdu和du数字对不上,先检查你是不是拿一个FAT镜像里的路径去跟宿主机路径对比了。
5.2 中文文件名乱码
mtools默认字符集处理对中文并不友好。如果你镜像里的文件名是中文,在用mdu或mdir查看时可能会显示成乱码,这在处理一些国内设备导出的镜像时非常常见。
解决方法是在配置或命令行里指定字符集:
bash复制mdu -i /tmp/test.img ::/中文目录
mtools -i /tmp/test.img ::/
更稳妥的方式是在~/.mtoolsrc里加一行:
code复制mtools_skip_check=1
这行不是解决字符集的,是跳过mtools对设备的检查。字符集问题的正确解法是设置MTOOLS_LOWER_CASE或者使用内建的codepage设置。比如:
code复制mcopy -i /tmp/test.img -s -D o /本地文件 ::/远程中文路径
但说实话,如果镜像里中文文件名非常多,我通常直接改用mount + nls=utf8的方式挂载,处理起来更省心。mdu更适合文件名为英文或数字的工程场景。
5.3 mdu不能处理NTFS、ext4这些非FAT文件系统
mdu的名字虽然带个“m”,但它只认MS-DOS文件系统(FAT12/16/32),不认NTFS,也不认Linux原生文件系统。如果你把mdu -i指向一个NTFS镜像,它会报错:
code复制init: Cannot open /tmp/test.ntfs (No such file or directory)
或者更常见的是,mount检查失败。这种情况下你要换工具:NTFS用ntfsls或ntfs-3g挂载后用du;ext4直接用debugfs或挂载后用du。
这里有个实际经验:在做磁盘管理时,先确认文件系统类型再选工具。可以用file /tmp/test.img快速查看,它会输出类似“DOS/MBR boot sector, FAT (32 bit)”的信息。从这个输出你一眼就知道该不该用mdu。
5.4 用mdu前先检查mtools配置的常见错误
mdu报“Cannot open ...”这类错误时,除了文件系统类型不对,还有两种常见原因:
- 镜像文件路径写错了,或者没有读权限。
- mtools配置里盘符映射指向了不存在的文件。
我在一开始用mtools时最常犯的错是:配置文件里写了drive m: file="/tmp/test.img",但实际的镜像文件叫test2.img,于是mdu m:/直接报错,我还以为是命令坏了,后来用mtools -v查看当前配置才发现是盘符映射的问题。
排查这类问题的方法:先执行mtools -v,它会输出当前生效的配置文件和盘符映射。然后ls -l确认镜像文件存在且当前用户可读。最后再跑mdu。这个排查顺序能解决九成以上的“mdu打不开设备”问题。
6. 写在最后的实用经验
如果让我只留一条mdu使用建议,那就是:把它放进你处理FAT映像的标准流程里,不管是一次性手工操作还是自动化脚本,都先mdu后行动。我自己的习惯是,每次用mcopy向镜像传完文件后,立刻执行mdu -s看一眼总占用,确认没有超限再继续下一步。这个习惯帮我避免过至少三次“镜像做好了才发现空间不足”的尴尬场面。
一个小技巧收尾:mdu其实也支持直接跟多个路径参数,比如mdu -i /tmp/test.img ::/firmware ::/scripts,可以一次统计多个目录。但如果目录数量太多,输出会乱,建议还是用-s配合目录列表来做。另外别忘了,mtools里还有mdir -f可以查看卷的剩余空间,跟mdu搭配使用会更完整——先用mdir -f看总量,再用mdu看明细,一纵一横,对一个FAT镜像的空间状况就有了完整的把握。
