![报告目录中的内容存在于其他地方,即使是分散的](https://linux22.com/image/143665/%E6%8A%A5%E5%91%8A%E7%9B%AE%E5%BD%95%E4%B8%AD%E7%9A%84%E5%86%85%E5%AE%B9%E5%AD%98%E5%9C%A8%E4%BA%8E%E5%85%B6%E4%BB%96%E5%9C%B0%E6%96%B9%EF%BC%8C%E5%8D%B3%E4%BD%BF%E6%98%AF%E5%88%86%E6%95%A3%E7%9A%84.png)
我想生成一份我知道可以安全删除的目录报告(即使需要快速手动验证),因为我知道完整的内容一直存在于其他地方 -即使,特别是如果重复文件随机散布在卷上的其他位置,可能以完全不同的目录布局,以及相关目录中不存在的文件之间。
换句话说,目录结构和内容不会相同。但是 100% 包含的文件将单独复制......在同一个 FS 上的某个地方、任何地方。
鉴于下面的工作流程和用例,应该清楚这几乎总是一种单向关系。 dir1 的 100% 文件内容可能存在于其他地方,具有不同的文件名和目录结构,通常每个文件有多个副本。
例如,dir1/file1 的副本可能存在于 dir2 和 dir3 中。 dir1/file2 的副本可能存在于 dir2 和 dir4 中。 dir2、dir3 和/或 dir4 还可能包含它们自己的唯一文件,以及其他目录中的文件的副本。但 dir1 绝对可以安全删除。
换句话说,不存在逆相关性:dir1 具有 100% 的冗余分散;但是 dir2、dir3、dir4...等等。不一定会。 (它们本身可能是删除候选者,因此也可能是删除候选者,但目前主要的候选者是 dir1。)
为了理解和回答这个问题,这个问题的其余部分并不是严格必要阅读的。它只是回答了一些潜在的离题“为什么?”以及“你尝试过……吗?”问题。
这是生成需求的用例,实际上似乎相当常见(或者至少并不罕见)。 ...至少最终结果有所不同:
- 地点:
- 我拍摄了 GB 的照片和视频。
- 每天,我都会将文件从存储卡移动到按相机名称和日期组织的文件夹中,然后移动到便携式 USB HDD 的冗余阵列上。
- 当我有时间的时候,我会组织副本将这些文件放入“(照片|视频)/年份/日期”之类的文件夹结构中,文件名前面带有“yyyymmdd-hhmmss”。 (换句话说,原始结构完全被打乱。而且并不总是以这种可预测的方式。)这些组织好的副本位于 SSD 驱动器上,以实现更快的工作流程,但我将原始的非托管副本留在缓慢的冗余存储上,以进行备份,除了复制步骤之外,副本在物理上是分开的。
- 回到家:
- 我将所有非托管文件从 USB HDD 阵列移至“永久”(更大、更强大且持续云备份)阵列,作为原始事实来源,以防我的工作流程出现问题。
- 对 SSD 上组织好的副本进行后处理。 (除了重命名之外,保持原始原始文件不变,并将更改保存到新文件。
- 一旦我完成并完成了对结果的预期操作,我将整个 SSD 文件结构移动到与原始文件相同的更大“永久”阵列上。 (但请记住,目录结构与原始 SD 卡转储结构完全不同。)
理想情况下,在该工作流程中,我还会删除现在不需要的原始卡转储文件夹。问题是,就像在生活中一样,我的工作流程不断被中断。要么我没有时间在现场完成组织工作,要么回家后就被搁置了一段时间,要么我每次都没有以完全相同的方式组织,要么我只是对存在的地方和存在的东西感到困惑害怕删除任何东西。通常在出发之前,我会将便携式媒体复制到永久阵列上以防万一,即使我怀疑它可能已经存在了 2 或 3 次。 (我不是强迫症。只是因经验而伤痕累累。)有时(后来的情况较少)我会重新组织我的整个逻辑目录结构。其他时候我会在中途更新它,而忽略以前的内容。多年来,我也搬过地方,完全不知道“卡片转储”文件去了哪里(以及如何去)。有时,我的现场工作流程虽然定义良好并经过测试,但会导致各种文件夹的状态不确定,因此我会制作更多备份副本“以防万一”。我还曾经编写过可以创建数千个文件夹符号链接的程序,以便以不同的方式查看我庞大的文件夹结构。 (就像文件系统“数据透视表”。)但后来将整个文件系统同步到替换数组,同时忘记设置“保留硬链接和符号链接”标志,并最终得到以前显然只是链接的副本,然后随着时间的推移,我们已经不知道哪些才是真正的原件了。 (尝试使用 20 年的照片/视频以及 30 年的其他数据进行此操作,以获得更好的结果!)
换句话说,我到处都有数百万个大文件,其中大部分都是不必要的冗余,而且乱七八糟。我需要修复它。不仅仅是为了节省空间(早已被处理),而是为了减少安全(更重要的是规范)位置的混乱。对我来说,第一步是删除数千个文件夹,其中的内容我非常有信心(不一定确定)100%分布在其他地方。即使每个删除候选者都需要快速的手动验证。
它正在生成初始列表,这对于人类来说在一生中是不可能的。理想情况下,该列表将是“该目录中的所有文件都存在于其他地方,但处于不同的目录布局中,这些目录还包含不匹配的文件”。但至少,“该目录中的所有文件也存在于其他地方”。
我研究并测试了大约十几种重复数据删除解决方案,其中一些解决方案非常接近于解决这个问题,但还不够接近。我的“永久”阵列多年来一直启用内联 ZFS 重复数据删除功能。尽管它将写入吞吐量减少到大约 25%,但我可以等待,但我无法承担数十年来两次甚至三次重复照片所需的数千美元的额外驱动器空间和视频数据(更不用说存储在三向镜条上)。
我刚刚配置了一个本地自动备份阵列(以补充云备份)。我选择了 Btrfs RAID1,以避免使用同一存储软件同时出现相同错误的潜在问题。 (我以前使用 ZFS 时也遇到过这种情况,幸运的是,只是导致暂时无法挂载。)此外,该解决方案还具有一个出色的功能,即能够轻松地纵向扩展或横向扩展阵列,一次一个磁盘。 :-),这很好,因为这对我的大型主 ZFS 阵列来说是一个非常昂贵且耗时的提议。
不管怎样,与这个问题相关的唯一原因是 Btrfs 有大量用于离线重复数据删除的优秀实用程序,正如我所说,其中一些非常接近解决这个问题,但还不够。我尝试过的快速总结:
- 查找:快速匹配算法,非常适合通过硬链接进行重复数据删除。问题是,这可能会给任何用户(所有用户?)带来灾难。虽然部分可以满足我在大型冗余媒体文件之间节省空间(无论名称或位置如何)的明显独立要求,但我发现这对于其他无法轻易解决的事情来说是灾难性的。例如,它还将其他没有关系的相同文件硬链接在一起。例如,操作系统和应用程序自动生成的各种元数据文件,其中大多数在数百或数千个目录中都是相同的,但绝对必须能够不同。例如“Thumbs.db”,引用同一个文件可能并且几乎肯定会导致稍后丢失数据——可能是微不足道的,也可能不是。)它确实有一个用于删除重复 Btrfs 引用链接的选项(稍后可以与 CoW 区分开来),但是该功能被标记为“实验性”。
- 杜佩删除:使用 Btrfs 引用链接进行重复数据删除,因此这是一种可接受的(很好的、甚至是)方法,可以节省磁盘空间,同时允许文件稍后分散。 (除了目前 Btrfs 在碎片整理时显然不会对文件进行重复数据删除 [取决于内核?],甚至是快照。多么可怕的怪癖,但我通过从不进行碎片整理并接受后果来避免它。) duperemove 的问题在于,因为它盲目地对搜索中的每个文件进行校验和,它的速度非常慢,并且会长时间且辛苦地消耗磁盘。它基本上执行穷人的阵列清理。我的阵列需要几天时间。 (bedup、bees 和其他一些在这方面是相似的,即使在其他方面非常不同。rdfind 和其他一些更聪明。它们首先比较文件大小。然后是前几个字节。然后是最后几个字节。只有当所有这些都匹配时,它是否诉诸校验和)
- 林特:目前这似乎最适合我节省磁盘空间的其他要求。它有两个 Btrfs 重新链接选项(内核模式原子克隆和稍微不太健壮的“cp --reflink”方法)。扫描算法是我测试过的最快的;散列可以提高到 sha256 或更高(包括逐位);它有许多有用的选项可以满足我的许多要求。 (据我所知,除了这个问题中的那个。)
还有许多其他重复数据删除实用程序,包括 fdupes、fslint 等。我几乎已经测试(或阅读)了它们,即使它们没有 Btrfs 支持(因为这与这个问题大多无关)。除了 rmlint 之外,它们中没有一个能够接近我需要的功能。
答案1
您可以使用 fdupes 等程序从两个相同的文件创建到一个文件的硬链接。这已经具有节省磁盘空间的好处。
执行此操作后,如果您有一个目录仅包含链接计数大于 1 的文件,则您知道每个文件都存在于磁盘上的其他位置。
要查找仅包含链接计数大于 1 的文件的目录,可以使用find
获取所有目录的列表,然后再次使用 find 来消除包含链接计数为 1 的文件的目录。
此示例不处理文件名或目录名中的空格。
for dir in `find . -type d`; do
if test -z "$(find $dir -maxdepth 1 -links 1 -quit)"; then
echo $dir
fi
done