fdupes或jdupes是首选工具,因其基于md5/sha哈希与字节级比对,支持递归扫描、自动跳过空文件和权限错误,并提供交互式删除;而diff一次仅比两个文件,cksum碰撞率高、非加密哈希,不适用于可靠去重。

直接用 fdupes 或 jdupes,别手写 find + md5sum 管道链——除非你明确需要无依赖、可审计的纯命令行流程。
为什么不用 diff 或 cksum 直接比对
diff 一次只能比两个文件,目录里有几千个文件时根本不可行;cksum 虽快但碰撞概率比 md5sum 高得多,尤其在大量小文件场景下容易误报。实际测试中,cksum 在同一批 PDF 或日志片段中出现过两次哈希冲突(4073570409 多次对应不同内容),而 md5sum 在相同样本中未出现。
-
diff file1 file2输出为空 ≠ 内容一致(比如二进制零填充差异可能被静默忽略) -
cksum输出是 32 位整数 + 字节数,不是加密哈希,不适用于内容去重 - 真正要靠哈希识别重复,必须用
md5sum、sha256sum这类固定长度输出的工具
fdupes 是最省事的选择
它默认递归扫描、自动跳过空文件和不可读文件、支持交互式删除,且比手工管道快 3–10 倍(内部用内存哈希表缓存,避免重复读盘)。
- 安装:
sudo apt install fdupes(Debian/Ubuntu)或sudo dnf install fdupes(Fedora/RHEL) - 只列出重复组:
fdupes -r /path/to/dir - 显示每组第一个为“原始”,其余标为“duplicate”:
fdupes -r -f /path/to/dir - 交互式确认删哪几个:
fdupes -r -d /path/to/dir(会逐组提示保留哪个) - 注意:
fdupes默认不比较硬链接——如果两个路径指向同一 inode,它会直接跳过,不视为重复
find + md5sum 管道链怎么写才不翻车
手动组合的问题不在逻辑,而在边界处理:空文件、权限错误、含空格路径、大目录性能崩塌。下面这条是经过验证的最小可靠版本:
find /path -type f ! -size 0 -not -path "/dev/*" -not -path "/proc/*" -not -path "/sys/*" -print0 | xargs -0 md5sum 2>/dev/null | sort | awk '{if ($1 == prev) {print prev_file; print $0} else {prev = $1; prev_file = $0}}'
-
! -size 0必须加,否则所有空文件都变成d41d8cd98f00b204e9800998ecf8427e,假阳性爆炸 -
-print0和xargs -0缺一不可,否则含空格或换行的路径直接让md5sum报No such file -
2>/dev/null要放在xargs后面,不是find后面——否则权限错误仍会中断管道 - 别用
uniq -d直接筛哈希值,它只去重相邻行;必须用awk做状态保持,否则漏组
什么时候该换用 rdfind
当你需要区分“原始文件”和“副本”,并批量替换成硬链接(节省空间又保全访问路径),或者要处理跨文件系统、大量小文件(rdfind 比 fdupes 更合适。
-
rdfind -dryrun true /path先看它怎么认定“原始”——规则是:先遇到的、路径更深的、mtime 更老的,三者叠加 -
rdfind -makehardlinks true /path把重复项全换成硬链接,ls -i可验证 inode 是否一致 - 注意:
rdfind默认把空文件当有效输入,要用-ignoreempty true显式关掉 - 它的
results.txt是结构化文本,方便 grep 或 awk 提取特定组,比fdupes的纯文本输出更适合后续脚本处理
真正容易被忽略的是:没有一种方法能 100% 安全判定“内容相同”。MD5 在极端情况下可能碰撞;硬链接在跨文件系统时失败;rdfind 的“原始”判断依赖扫描顺序——如果你在 NFS 挂载点上跑,顺序可能每次都不一样。务必先在子目录试跑,再重定向输出到文件人工抽检几组。











