jdupes 找到重复文件以后,可以用四种完全不同的方式处理它们:
-B --dedupe:让重复文件共享底层数据块;-l --link-soft:把重复副本替换为相对符号链接;-L --link-hard:把重复副本替换为硬链接;-d --delete:交互选择要保留的文件,并删除其余副本。
这四个选项都能减少重复数据,但不能简单理解为四种写法不同的“删除重复文件”。
它们改变的是不同层次的对象:数据块、inode、路径引用或目录项。
选择错误时,最麻烦的往往不是当场报错,而是几个月后某个程序修改、移动或删除文件,才发现其他路径也受到了影响。
本文从文件系统规格和行为出发,说明四种模式的真实区别、适用场景、限制条件和验证方法。
特别提醒:
jdupes -d是会删除文件的操作。不要把同一个目录重复写入命令行,也不要在没有充分理解符号链接遍历行为时把-d与-s或--symlinks一起使用。
先看结论:四种方式的核心区别
| 选项 | 处理结果 | 路径是否保留 | inode 是否独立 | 后续修改是否相互影响 | 主要限制 |
|---|---|---|---|---|---|
-B --dedupe |
共享相同物理数据块 | 全部保留 | 是 | 通常不影响,写入时 CoW 分离 | 文件系统必须支持去重或克隆接口 |
-l --link-soft |
副本变为相对符号链接 | 路径名保留,但类型变为 symlink | symlink 自有 inode,内容来自目标 | 修改链接指向的内容会修改目标文件 | 目标移动或删除后可能成为断链 |
-L --link-hard |
多个路径指向同一 inode | 全部保留 | 否 | 会影响,因为本质是同一个文件 | 不能跨文件系统,应用语义可能变化 |
-d --delete |
删除未被选择保留的副本 | 只保留选中的路径 | 不适用 | 不会联动,但被删路径彻底消失 | 选择错误会直接丢失路径和元数据 |
如果只记住一句话,可以这样判断:
- 希望各个文件仍然独立,且文件系统支持 CoW:优先考虑
-B; - 明确需要多个文件名共同代表同一个文件:考虑
-L; - 明确希望某些路径只是另一个文件的引用:考虑
-l; - 确认多余路径没有保留价值:才使用
-d。
jdupes 如何确认两个文件相同
处理方式虽然不同,但前面的重复文件识别流程相同。
按照 jdupes 官方手册,默认匹配过程依次包括:
- 比较文件大小;
- 比较部分文件哈希;
- 比较完整文件哈希;
- 最后进行逐字节比较。
只有通过这些阶段的文件,才会进入同一个重复文件集合。
因此,默认模式并不是“文件名相同就算重复”,也不是“哈希相同就立即执行操作”。
不带任何动作选项时,jdupes 默认只打印重复文件集合:
|
|
不同集合之间以空行分隔。
在真正使用 -B、-l、-L 或 -d 以前,应当先运行一次只读扫描,确认路径范围和匹配结果符合预期。
不要为追求速度绕过最终校验
-Q --quick 会跳过逐字节确认,只依赖哈希结果。
官方手册明确把它标记为存在数据丢失风险。
-T --partial-only 的风险更高,因为它只依据文件开头的部分哈希进行匹配。
在执行删除、链接或 CoW 去重时,不应为了缩短扫描时间而随意加入这两个选项。
本文后续示例均使用默认的完整确认流程。
-B --dedupe:保留独立文件,共享数据块
基本命令如下:
|
|
-B 会请求文件系统对重复文件执行底层去重。
官方手册把这一过程称为 copy-on-write、CoW、cloning 或 reflink 去重。
从目录层看,原来的文件名都还在。
从 inode 层看,它们仍然是彼此独立的文件。
从数据块层看,相同内容可以引用同一组物理块,从而减少实际占用空间。
CoW 去重后的结构
假设有两个完全相同的文件:
|
|
两个路径对应不同 inode,但相同区段共享底层数据块。
如果以后修改 b.iso 的一部分,支持 CoW 的文件系统会为变化的区段分配新块:
|
|
未修改的区段仍可共享,发生写入的区段则分离。
这正是 -B 与硬链接最关键的区别。
为什么它适合仍可能被修改的文件
使用硬链接时,多个路径实际上是同一个 inode。
程序通过任一路径原地写入内容,其他路径看到的内容也会改变。
使用 CoW 去重时,文件仍然独立。
只要文件系统正确实现 CoW,修改一个文件不会把另一个文件同步改掉。
因此,以下场景通常更适合 -B:
- 多份虚拟机镜像;
- 多个版本的备份目录;
- 照片或视频素材副本;
- 软件仓库中的重复安装包;
- 内容相同但生命周期不同的文件。
-B 的文件系统要求
-B 不是 jdupes 自己重新压缩或搬运文件内容。
它依赖操作系统和文件系统提供的同区段去重或克隆接口。
官方手册列出的支持对象包括:
- Btrfs;
- 启用 reflink 特性的 XFS;
- Apple APFS。
具体能否工作还取决于内核、挂载环境、jdupes 编译特性和文件系统格式化参数。
对于 XFS,仅仅看到文件系统类型是 XFS 还不够;文件系统创建时必须启用 reflink 能力。
可以先查看文件系统类型:
|
|
XFS 可进一步查看文件系统信息:
|
|
不要仅凭命令没有明显报错,就认定所有重复数据都已经释放。
如何验证 CoW 去重结果
先确认文件仍然拥有不同 inode:
|
|
如果两个 inode 不同,这是预期现象。
但 stat 显示的块数不一定能直接、准确地表达共享区段。
不同文件系统对共享块统计方式可能不同。
还可以比较去重前后的文件系统可用空间:
|
|
对于 Btrfs,可结合文件系统专用工具观察空间分配:
|
|
测试时应使用可丢弃的样本,分别修改其中一个文件,然后校验另一个文件的哈希没有变化。
-B 的局限
CoW 去重并不等于“零成本”。
共享区段需要文件系统维护引用关系。
后续写入会触发新块分配,并可能产生额外碎片。
对高频随机写入的数据、数据库文件或持续变化的虚拟磁盘,应先评估写入放大和碎片影响。
快照也可能让空间统计变得更复杂。
删除一个目录中的文件后,共享块若仍被另一个文件或快照引用,就不会立即释放。
如果你的重点是 Btrfs 和 NAS 场景,可继续参考站内的 Btrfs + jdupes CoW 去重实践。
-L --link-hard:让多个路径成为同一个文件
基本命令如下:
|
|
-L 会把每组重复文件中的其他副本替换为指向第一个文件 inode 的硬链接。
处理完成后,多个路径名称仍然存在,但它们不再是独立文件。
硬链接后的结构
处理前:
|
|
处理后:
|
|
此时 a.bin 和 b.bin 是同一个 inode 的两个目录项。
它们不只是“共享内容”,而是同一个文件拥有两个名字。
修改任一硬链接会发生什么
如果程序直接打开 b.bin 并覆盖其中的字节,a.bin 读取到的内容也会改变。
因为两条路径最终访问的是同一个 inode。
文件权限、所有者和时间戳等 inode 元数据同样不再彼此独立。
但有一个容易混淆的例外:
有些编辑器并不是原地修改文件,而是创建临时文件,再用重命名替换原路径。
这种“写新文件再替换”的保存方式会让被替换的路径获得新 inode,从而解除硬链接关系。
所以不能仅凭一次编辑测试,就推断所有应用程序都具有相同行为。
硬链接不能跨文件系统
硬链接只能在同一个文件系统内创建。
即使两个挂载点都使用 ext4,设备或文件系统实例不同,也不能跨越边界建立硬链接。
可以用下面的命令查看设备号和 inode:
|
|
处理成功后,两条路径的设备号和 inode 应当相同,链接计数通常会增加。
也可以使用:
|
|
删除一个硬链接路径不会立即删除内容
删除 b.bin 只是移除其中一个目录项。
只要 a.bin 仍然指向该 inode,文件数据就仍然存在。
只有最后一个硬链接被删除,并且没有进程继续打开该文件时,文件系统才会回收相应对象和数据块。
这与符号链接的“目标路径消失后留下断链”完全不同。
什么时候适合使用 -L
硬链接适合这些前提明确的场景:
- 文件位于同一个文件系统;
- 多个路径在业务上确实可以视为同一个对象;
- 文件预计只读或内容不会再被原地修改;
- 备份、同步、索引和权限管理软件能够正确处理硬链接;
- 不需要每个路径拥有独立的 inode 元数据。
典型例子包括只读软件包缓存、不可变归档副本和受控的媒体资源库。
什么时候不要使用 -L
以下情况应谨慎或避免使用:
- 某个副本可能被应用原地修改;
- 文件分别属于不同用户或权限策略;
- 备份软件可能把硬链接展开成多份数据;
- 同步软件可能不保留硬链接关系;
- 应用依赖 inode 唯一性识别文件;
- 文件跨越多个文件系统或网络挂载点。
如果两个路径现在内容相同,但未来职责不同,内容相同并不代表它们应该成为同一个 inode。
-l --link-soft:把副本替换为相对符号链接
基本命令如下:
|
|
-l 会保留每组中的第一个文件,并把其他重复文件替换为指向它的相对符号链接。
假设处理前有:
|
|
处理后第二个路径可能表现为类似关系:
|
|
实际相对路径由目录位置决定。
相对符号链接意味着什么
符号链接保存的是目标路径文本,而不是目标 inode 的额外名称。
相对链接的解析起点是符号链接所在目录,不是运行命令时的当前工作目录。
因此,整体移动一棵内部结构不变的目录树时,相对符号链接通常仍能工作。
但是,只移动链接或只移动目标,就可能让关系失效。
软链接与硬链接的行为差异
软链接可以跨文件系统。
硬链接通常不能跨文件系统。
软链接拥有自己的文件类型和 inode。
硬链接只是同一普通文件 inode 的另一个名称。
软链接目标被删除或改名后,链接可能变成断链。
删除一个硬链接名称时,只要还有其他硬链接,内容仍然可访问。
软链接可以指向目录;本文讨论的 jdupes 动作针对重复文件集合。
软链接会改变文件类型
执行 -l 以前,两个路径都是普通文件。
执行以后,其中一个仍是普通文件,其他路径变成符号链接。
这会影响某些应用:
- 安全策略可能拒绝跟随符号链接;
- 容器或沙箱可能看不到链接目标;
- Web 服务可能禁止访问链接指向的路径;
- 备份软件可能只备份链接本身;
- 文件监控程序可能对链接和目标产生不同事件;
- 权限检查最终会落在目标路径及其父目录上。
所以,“文件还能打开”并不等于应用兼容性已经验证。
如何验证软链接
查看链接保存的目标文本:
|
|
解析最终目标:
|
|
检查目录树中的断链:
|
|
find -xtype l 会找出最终目标无法解析的符号链接。
在正式使用前,还应测试移动目标文件、移动上级目录、备份恢复和应用读取等操作。
什么时候适合使用 -l
软链接适合“引用关系本来就合理”的场景:
- 希望显式指定一个权威副本;
- 其他路径本来就只是入口或兼容路径;
- 需要跨文件系统引用;
- 应用明确支持符号链接;
- 能够保证目标路径的生命周期。
如果目录树经常被拆分、单独同步或分别打包,软链接通常不是理想选择。
-d --delete:选择保留项,删除其余副本
基本命令如下:
|
|
-d 会针对每组重复文件提示用户选择要保留的路径,然后删除其余路径。
这是四种方式里最直观的一种,也是最不可逆的一种。
-B、-L 和 -l 都会在一定形式上保留原来的路径入口。
-d 则真正移除未保留文件的目录项。
删除重复内容不等于没有信息损失
两个文件的内容完全相同,并不代表两条路径没有各自价值。
不同路径可能表达不同的:
- 目录分类;
- 文件名语义;
- 所属项目;
- 访问控制上下文;
- 备份保留策略;
- 应用索引关系;
- 用户工作流程。
jdupes 判断的是文件内容是否重复,不会替你判断哪个目录项具有业务意义。
因此,删除前需要同时审查内容和路径。
最重要的风险一:不要重复指定同一个目录
不要这样运行:
|
|
也要避免通过不同写法把同一棵目录树传入两次,例如:
|
|
官方文档警告:当同一个目录被指定多次时,同一文件可能以“自己的重复项”形式出现在集合中。
如果用户在这种混乱的集合里保留了一个显示项,却删除了代表同一真实文件的另一个显示项,就可能造成数据丢失。
执行前应把所有输入路径规范化,并确认它们没有重复、别名或意外重叠。
可以先检查真实路径:
|
|
还要留意 bind mount、符号链接目录和容器映射是否让同一内容从多个入口被遍历。
最重要的风险二:谨慎组合 -d 与 -s
-s 或 --symlinks 会跟随符号链接目录。
当它与 -d 同时使用时,交互列表可能同时出现符号链接相关路径和被指向的真实文件。
官方手册指出,用户可能误保留符号链接,却删除它所指向的文件。
结果就是看似保留了一个路径,实际上只留下无法访问目标的链接。
除非已经完整绘制并核对符号链接关系,否则不要使用:
|
|
更稳妥的做法是先不跟随符号链接,分开检查真实目录和链接结构。
-N --no-prompt 会把删除变成自动操作
-N 与 --delete 一起使用时,会自动保留每组的第一个文件并删除其余文件。
例如:
|
|
这不是普通的“跳过确认”,而是把“第一项是谁”直接变成保留策略。
若确实需要自动化,应先理解:
-o name默认按文件名排序;-o time可按修改时间排序;-i会反转排序;-O --param-order会优先保留命令行参数顺序对结果集合的影响。
自动删除前,应在同样的路径、排序和递归选项下先执行只读扫描,并保存结果供审计。
对没有可靠备份的数据,不建议直接使用 -d -N。
四种模式对权限和元数据的影响
默认情况下,jdupes 的核心目标是判断内容重复。
但内容相同的文件可能有不同的所有者、组或权限位。
-p --permissions 可以要求所有者、组和权限位不同的文件不要被视为重复项:
|
|
这对 -L 尤其重要。
硬链接后多个路径共享 inode 元数据,不可能继续保持各自不同的属主和权限位。
对 -d 来说,选择保留哪一个路径也会决定最终留下哪份文件元数据。
对 -l 来说,访问内容时最终受目标文件和路径遍历权限控制。
对 -B 来说,文件 inode 仍然独立,因此各自的权限和大部分元数据可以继续独立存在。
如果还依赖 ACL、扩展属性、SELinux 标签或文件能力,应使用对应工具额外核查。
仅比较传统权限位,并不代表所有扩展元数据都已纳入业务判断。
跨文件系统时怎么选
扫描多个挂载点时,可以加入:
|
|
-1 --one-file-system 会阻止跨文件系统或设备匹配。
这能减少后续动作遇到能力边界的概率。
四种模式在跨文件系统方面的差异如下:
-B依赖文件系统接口和共享区段能力,通常需要目标位于兼容范围内;-L无法创建跨文件系统硬链接;-l可以保存跨文件系统的路径引用,但目标挂载缺失时链接不可用;-d可以删除不同文件系统上的副本,但必须确认保留项所在存储长期可用。
例如,把本地副本删掉,只保留可拔移动硬盘或临时网络挂载上的副本,技术上可能成功,业务上却非常危险。
一套稳妥的执行流程
不要直接把动作选项加到生产目录上。
建议按以下顺序执行。
第一步:确认备份或快照可恢复
快照存在不代表一定可恢复。
至少确认:
- 快照覆盖本次扫描的所有目录;
- 快照创建时间早于去重动作;
- 快照不会与生产目录共享同一故障域;
- 已知道恢复单个文件和整个目录的方法;
- 恢复操作经过抽样测试。
硬链接和符号链接还需要确认备份工具是否保留链接语义。
第二步:确认输入路径没有重复
列出准备扫描的每一个目录:
|
|
检查它们是否:
- 指向同一真实目录;
- 一个目录完整包含另一个目录;
- 通过符号链接再次进入同一目录树;
- 通过 bind mount 或网络挂载出现别名;
- 因 shell 通配符展开而重复。
尤其在使用 -d 时,任何不清楚的重叠都应先消除。
第三步:先做只读扫描
|
|
把输出保存到审核文件:
|
|
这里没有使用动作选项,因此只输出匹配集合。
逐组检查哪些路径应该保留独立语义,哪些只是冗余副本。
第四步:在小型测试目录验证行为
创建一个可丢弃的测试目录:
|
|
先查看 inode 和哈希:
|
|
然后每次只测试一种动作。
测试硬链接:
|
|
要测试其他动作,应重新创建干净样本,不要在已经硬链接的文件上继续叠加测试。
第五步:一次只执行一种动作
不要把四种处理模式堆在同一条命令里。
根据目录职责拆分批次,例如:
|
|
|
|
|
|
|
|
这样更容易解释结果、验证变化和执行恢复。
第六步:操作后验证
无论选择哪一种方式,都至少执行这些检查:
|
|
|
|
|
|
再根据模式补充验证:
-B:确认 inode 独立,抽样修改一个副本后另一个不变;-L:确认 inode 相同,链接计数正确;-l:用readlink和realpath确认目标,检查断链;-d:根据审核清单确认该保留的路径仍存在。
最后让实际使用这些文件的应用执行一次读取、索引、备份或同步测试。
如何根据场景选择
NAS 媒体库和照片归档
如果底层是支持去重的 Btrfs,且文件可能被照片管理或媒体管理程序修改,优先评估 -B。
它能保留独立文件语义,降低硬链接联动修改的风险。
如果目录完全只读,而且应用能正确处理硬链接,-L 也可能有效。
软件包缓存和构建产物
不可变构建产物位于同一文件系统时,-L 通常简单高效。
但构建工具若会原地改写缓存文件,就应避免硬链接。
能随时重新生成的缓存,也可以直接使用 -d,但仍要确认删除不会破坏索引。
多版本备份目录
多版本目录需要每个版本保持独立视图。
支持 CoW 时,-B 通常比 -L 更符合这种语义。
硬链接也常用于增量备份,但必须由备份程序系统性管理,不能只凭“当前内容相同”临时替换。
兼容旧路径
如果一个权威文件需要从多个旧路径访问,而且软件支持符号链接,可以选择 -l。
这相当于明确告诉系统:其他路径只是引用。
目标路径必须稳定,并且备份、容器和权限策略都要覆盖它。
一次性清理下载目录
确认重复副本没有目录语义,且备份可用时,可以用交互式 -d。
先只读扫描,再逐组选择保留项。
不要为了省几次按键就立刻加入 -N。
常见误区
误区一:四种模式节省的空间完全一样
不一定。
-d、-L 和 -l 最终只保留一份普通文件内容,但仍有不同数量和类型的目录项或链接对象。
-B 的实际节省量取决于文件系统成功共享的区段、块大小、对齐、快照和后续写入。
误区二:硬链接是更可靠的软链接
两者语义不同,不能按“可靠程度”简单排序。
硬链接把多个名称绑定到同一 inode。
软链接保存一个可解析的目标路径。
前者没有“目标路径被改名就断链”的问题,后者则能跨文件系统并明确表达引用关系。
误区三:CoW 去重后两个文件就是硬链接
不是。
CoW 去重后的文件仍有独立 inode,只是共享部分或全部数据块。
硬链接则从 inode 层就是同一个文件。
用 ls -li 或 stat 可以观察这一差别。
误区四:内容相同就可以安全删除任意一个
内容相同只证明字节相同。
路径、文件名、权限、标签、业务归属和备份策略仍可能不同。
-d 的选择必须基于路径语义,而不只是文件内容。
误区五:相对软链接一定更便携
相对链接只有在链接和目标保持相对位置时才便携。
如果只复制其中一个子目录,链接可能立即失效。
打包、同步和容器挂载都可能改变原有目录关系。
误区六:删除后 df 一定立即增加可用空间
不一定。
文件可能仍被进程打开,也可能被快照、其他硬链接或 CoW 共享引用。
文件系统延迟回收和空间统计方式也会影响观察结果。
参考资料
最终选择建议
如果文件系统支持 CoW,而且希望文件以后还能独立修改,-B --dedupe 通常是四种方案中语义最温和的选择。
如果明确需要多个路径表示同一个不可变文件,并且都在同一文件系统,使用 -L --link-hard。
如果需要建立清晰的路径引用关系,并能接受目标移动后断链的风险,使用 -l --link-soft。
如果多余路径本身没有任何保留价值,而且已经有可靠恢复手段,再使用 -d --delete。
无论选择哪一种,都应遵循同一原则:
先只读扫描,核对路径,测试应用行为,再执行动作,最后验证文件系统和业务结果。
对 -d 再强调一次:不要重复指定同一目录,也不要在没有完整核对符号链接关系时与 -s 或 --symlinks 组合使用。
省下来的存储空间可以重新购买,丢失的目录语义和唯一副本却未必能够重建。