检测具有相同内容的重复文件夹

检测具有相同内容的重复文件夹

我经常有名称不同但内容相同的文件夹。

例如,我将一个文件夹复制到另一个位置,以便于访问,然后我忘记删除该副本。

如何检测具有相同内容的重复文件夹?

为了检测重复文件,我使用了 Czkawka,但没有找到类似的工具来检测重复文件夹。

类似问题:

检测重复的文件夹但忽略空文件夹的存在 https://stackoverflow.com/questions/43560796/how-to-find-duplicate-directories

检测重复的文件夹,但文件夹名称很重要 查找并列出重复的目录

答案1

林特有一个检测重复目录的功能:

-D --merge-directories (default: disabled)

从手册页:

使林特使用特殊模式,收集所有找到的重复项并检查整个目录树是否重复。谨慎使用:您始终应确保在 rmlint 或其删除脚本运行期间未修改所调查的目录。

重要信息:equal 的定义:如果两个目录包含完全相同的数据,则 rmlint 认为两个目录相等,无论包含数据的文件如何命名。想象一下,rmlint 从目录中找到的数据创建一个长的、排序的流,并以一种神奇的方式将其与另一个目录进行比较。这意味着默认情况下目录的布局并不重要。空文件也不会被视为内容。这可能会让某些用户感到惊讶,但请记住 rmlint 通常只关心内容,而不关心任何其他元数据或布局。如果您只想查找具有相同层次结构的树,您应该使用 --honour-dir-layout / -j。

答案2

解决这个问题最简单的方法当然是一开始就没有问题;您似乎关心的是不可变的文件集,因此cp -r original second您可以只使用 ,代替ln -s original second,并利用 Linux 已经允许您将任何文件夹或文件“镜像”到文件系统层次结构中的任何其他点的事实。

如果您需要更改数据的第二个实例中的文件的功能,我建议您使用引用计数文件系统(XFS、btrfs 等),并忽略您拥有副本的事实 – 您所使用的文件副本中没有更改,不使用任何额外空间。

现在,假设两者都不是一个选项:

由于您需要将所有目录与所有目录进行比较(幸运的是,这是无循环的,只要您停留在一个文件系统上并且不遵循符号链接),因此您需要在一棵树上执行重复的子树搜索。我不认为,不,我非常确定,shell 脚本不是您想要处理图形数据结构的环境。它会迅速爆炸 - 无论是对于 shell 的复杂性还是对于作为人类程序员的您来说。

因此,磨练你的 Rust、C++、Go、Erlang……并开始编码:

您需要编写一个重现目录结构的深度优先搜索算法,以在内存中准备目录树的表示。每个节点保存一个值(例如,一个64位整数)以及它是否已经被处理;最初,没有任何节点被标记为已处理。

然后,在该树中,您获取叶节点,即不包含其他目录的目录,并计算其中文件集的哈希值(以稳定、排序的方式,哈希值包含您关心的内容 - 修改时间、名称、大小、内容) ?...);该散列成为相应叶节点的值,您将该节点标记为已处理,并将其输入到散列映射中(使用节点值作为散列)。如果该值已经是哈希映射中的键 - 您检查实际身份(哈希函数不能保证!),并删除适当的副本,并从树中删除相应的节点。

将所有叶节点标记为已处理(甚至从树中删除它们)后,转到第一个叶节点的第一个父节点,并对目录内容进行哈希处理,这次将“标记已处理”节点视为常规节点具有自己适当的哈希值的文件。通过它,您可以获得第一个父节点的值;您将其标记为已处理,将其添加到哈希表中,必要时删除,然后移动到下一个叶节点并执行相同的操作。
当您执行该目录遍历时,您将删除叶节点以及叶节点的所有兄弟节点(它们仅位于一个目录中,并且树中“更高层”不能有相同的副本,因为这意味着不同的深度内的子目录)。

完成后,以前的“叶子的第二级”节点已成为叶节点:重复此操作,直到为根节点分配了值。

答案3

作为练习,我在 shell 中实现了一个重复目录查找器。

https://github.com/ilario/finddirdupes

它的第一个参数是要分析的文件夹,第二个参数是要考虑的最小目录大小(以字节为单位)。建议至少使用 5000,以避免检测到许多空文件夹。

./finddirdupes.sh ~/documents 10000

显然,它比rmlint -D另一条评论中报道的要慢得多。

答案4

此代码不会检查文件内容是否相同,因此您必须自己检查。

它根据大小和子文件夹以及包含的文件名称来比较文件夹。

运行之前,请检查命令-s选项是否ls -s适用于您的系统。

# avoid starting with a non-empty dirhash file
rm dirhash

# while reads all the folders list provided by find (the <<< is a here string, passing the find output as an input to read)
# cd enters the folder
# ls lists the content, -1 on only one column, -a including the hidden files, -s indicating the files size (check if this works on your system), -R recursively entering every subdirectory
# xxhsum calculates a string from the output of ls
# the XXH3 hashing algorithm was the one suggested on
# https://xxhash.com/#benchmarks.
# du calculates the total size of the folder
while read d; do cd "$d"; hash=$(ls -1asR | xxhsum -H3); size=$(du -s); cd "$OLDPWD"; echo $hash $size $d >> dirhash; done <<< $(find ./ -type d)

# sort sorts the file based on the dir size, and then on the hash
# uniq shows all the duplicates based on the first 38 characters, which include the hash and the size from du
sort -k5n,5 -k4,4 dirhash | uniq --all-repeated=separate -w 38

相关内容