让我们创建一些测试目录树:
#!/bin/bash
top="./testdir"
[[ -e "$top" ]] && { echo "$top already exists!" >&2; exit 1; }
mkfile() { printf "%s\n" $(basename "$1") > "$1"; }
mkdir -p "$top"/d1/d1{1,2}
mkdir -p "$top"/d2/d1some/d12copy
mkfile "$top/d1/d12/a"
mkfile "$top/d1/d12/b"
mkfile "$top/d2/d1some/d12copy/a"
mkfile "$top/d2/d1some/d12copy/b"
mkfile "$top/d2/x"
mkfile "$top/z"
Run Code Online (Sandbox Code Playgroud)
结构是: find testdir \( -type d -printf "%p/\n" , -type f -print \)
testdir/
testdir/d1/
testdir/d1/d11/
testdir/d1/d12/
testdir/d1/d12/a
testdir/d1/d12/b
testdir/d2/
testdir/d2/d1some/
testdir/d2/d1some/d12copy/
testdir/d2/d1some/d12copy/a
testdir/d2/d1some/d12copy/b
testdir/d2/x
testdir/z
Run Code Online (Sandbox Code Playgroud)
我需要找到重复的目录,但我只需要考虑文件(例如,我应该忽略没有文件的(子)目录).因此,从上面的测试树中得到的结果是:
duplicate directories:
testdir/d1
testdir/d2/d1some
Run Code Online (Sandbox Code Playgroud)
因为在两个(子)树中只有两个相同的文件a
和b
.(和几个目录,没有文件).
当然,我可以md5deep -Zr .
,也可以使用perl
脚本(使用File :: Find + Digest :: MD5或使用Path :: Tiny等)遍历整个树并计算文件的md5-digests,但这对于找到重复的目录 ...... :(
知道怎么做吗?老实说,我什么都不知道.
编辑
code
.(我能自己编码)EDIT2
背后的理由 - 为什么需要这个:由于错误的备份策略,我从许多外部硬盘驱动器复制了大约2.5 TB的数据.例如,多年来,整个$HOME
目录被复制到(许多不同的)外部硬盘驱动器中.许多子目录具有相同的内容,但它们位于不同的路径中.所以,现在我试图消除相同内容的目录.
我需要通过目录执行此操作,因为这里是目录,它有一些重复文件,但不是全部.让我们说:
/some/path/project1/a
/some/path/project1/b
Run Code Online (Sandbox Code Playgroud)
和
/some/path/project2/a
/some/path/project2/x
Run Code Online (Sandbox Code Playgroud)
例如,这a
是一个重复的文件(不仅是名称,而且也是内容) - 但这两个项目都需要它.所以我想保留a
两个目录 - 即使它们是重复文件.因此,我寻找一个"逻辑"如何找到重复的目录.
遍历可以识别您所描述的重复目录。我认为这是:如果一个目录中的所有文件都等于另一个目录中的所有文件,那么它们的路径是重复的。
查找每个目录中的所有文件并用它们的名称形成一个字符串。例如,您可以用逗号(或肯定不在任何名称中的其他序列)连接名称。这是要比较的。在此字符串前面添加路径,以便识别目录。
例如,可以通过用键填充散列来完成比较,该键是带有文件名的字符串及其值的路径。一旦发现密钥已经存在,您就可以检查文件的内容,并将路径添加到重复项列表中。
带有路径的字符串不必实际形成,因为您可以在遍历期间构建哈希和重复列表。如果需要的话,首先拥有完整的列表可以进行其他类型的核算。
总共只需编写很少的代码。
一个例子。假设你有
dir1/subdir1/{a,b} # 重复项(文件“a”和“b”被视为相等) 目录2/子目录2/{a,b}
和
proj1/subproj1/{a,b,X} # 不重复,因为有不同的文件 proj2/subproj2/{a,b,Y}
上述处方会给你带来字符串
'dir1/subdir1/a,b',
'dir2/subdir2/a,b',
'proj1/subproj1/a,b,X',
'proj2/subproj2/a,b,Y';
Run Code Online (Sandbox Code Playgroud)
其中(子)字符串'a,b'
标识dir1/subdir1
和dir2/subdir2
为重复项。
我不明白如何避免遍历来构建一个负责所有文件的系统。
上面的过程是第一步,不处理带有文件和子目录的目录。
考虑
目录A/目录B/ ab sdA/ a X sdB/ CDCCD
这里的路径dirA/sdA/
和dirB/sdB/
与问题描述重复,但整体dirA/
和dirB/
是不同的。这没有在问题中显示,但我希望它会引起兴趣。
可以为此修改第一部分的过程。遍历目录,在每一步形成一个路径组件。获取每个目录和所有子目录中的所有文件(如果没有,我们就完成了)。将逗号分隔的文件列表附加到路径部分 ( /sdA/
)。所以上式的表示就是
'dirA/sdA,a,b/c,d', 'dirB/sdB,a,X/c,d'
Run Code Online (Sandbox Code Playgroud)
对于发现已存在的每个文件列表子字符串 ( c,d
),我们可以逐个组件地对照现有子字符串检查其路径。现在,带有像这样的键的散列c,d
将不起作用,因为此示例对于不同的层次结构具有相同的文件列表,但需要修改的(或其他)数据结构。
最后,可能有更多与sdA
(例如sdA2
)平行的子目录。我们只关心它自己的路径,但并行文件除外(a,b
在路径的该组件中dirA/sdaA2,a,b/
)。因此,请记住所有底层文件列表 ( c,d
) 及其路径,如果文件列表相等并且路径长度相同,请检查它们的路径a,b
在每个路径组件中是否具有相等的文件列表。
我不知道这对您来说是否是一个可行的解决方案,但我希望“接近重复”的情况很少见——备份要么是重复的,要么不是。因此,可能没有太多需要处理复杂的蔓延层次结构中的进一步边缘情况。这个程序至少应该是一个有用的预选机制,这将大大减少进一步工作的需要。
这假设相同的文件名很可能表示相同的文件。其中一部分是我的期望,如果一个文件只是重命名,它仍然不能被视为重复。如果不是这样,这种方法将不起作用,并且需要类似于jm666 的答案的东西。
归档时间: |
|
查看次数: |
1632 次 |
最近记录: |