Linux:比较目录结构而不比较文件


55

比较两个目录结构而不实际比较文件中数据的最佳和最简单方法是什么?这工作正常:

diff -qr dir1 dir2_

但这确实很慢,因为它也在比较文件。是否有一个用于diff的开关或另一个简单的cli工具来做到这一点?


“目录结构”是指目录路径,还是目录文件和非目录文件的路径?
直觉

是的,文件夹文件。
约拿(Jonah)2010年

1
在这种情况下,您应该-type d从@slartibartfast的答案中删除该选项,或者查看我的答案。
直觉

Answers:


36

以下内容(如果您将第一个目录替换为directory1,将第二个目录替换为directory2)应立即执行所需的操作:

find directory1 -type d -printf "%P\n" | sort > file1
find directory2 -type d -printf "%P\n" | sort | diff - file1

基本原理是,它打印出所有目录,包括相对于基本目录N目录的子目录路径。

如果您在某些目录名称中有回车符,而在其他目录中没有回车符,则可能会下降(产生奇怪的输出)。


这对我没有好处,因为如果一个目录包含一个文件夹,其中包含数千个文件,则这些文件都将单独列出,而diff -rq只是显示根目录存在于其中,然后继续。
克里斯·杰弗逊

正如直觉指出的(几年前),为回答OP问题,应该删除-type d,以便在比较以及目录中考虑文件
user2746401

我理解并尊重对问题陈述的阅读。那不是我当时的读物。您是否建议我编辑答案以回答更新的问题?我可以这样做,如果您认为这对某些人有帮助,那么我可以将解决方案和评论设置为现在的样子,这似乎是相当有效的。
Slartibartfast

34
vimdiff <(cd dir1; find . | sort) <(cd dir2; find . | sort)

将为您很好地并排显示两个目录层次结构,并折叠所有公共部分。


该解决方案随机失败。当vim读取(或重新读取)临时文件描述符时,它已经不存在了。
DenilsonSáMaia

23

我通常rsync用于此任务:

rsync -nav --delete DIR1/ DIR2

请务必始终使用-n,aka--dry-run,选项,否则它将同步(更改目录的内容)。

这将根据文件修改时间和大小比较文件...我这就是您真正想要的,或者至少您不介意这样做吗?我感觉到您只是希望它发生得更快,而不是您需要它忽略文件内容之间的差异。如果您确实希望它不列出具有相同名称的不同文件,那么我认为添加该--ignore-existing选项即可。

另外要注意,不要把一个/在结束DIR1将导致其比较目录 DIR1内容DIR2

输出最终有点冗长,但是它将向您显示哪些文件/目录不同。存在于DIR2和不存在于其中的文件/目录DIR1将以单词开头deleting

在某些情况下,@ slartibartfast的答案可能更合适,尽管您需要删除-type d启用非目录文件列表的选项。 rsync如果您要比较的文件/目录数量很多,则速度会更快。


极好的答案。在rsync的输出中,很难注意到deleting...文本,但这可能是在保持速度的同时比较文件的更好方法之一。当不需要差异文件时,这里的其他答案会更快...就像在OP的示例中一样,但我真的很喜欢这一点。
乔尔·梅隆

这就是我所追求的。我在一对庞大的目录树中有一些大小不同的文件,我想知道哪个文件。这仅在几秒钟内就达到了该目标。
suprjami 2015年

最好与具有只读访问权限的用户一起运行它。如sudo -u nobody rsync -nav --delete d1 d2前提是“其他”的标志允许阅读。
user1182474 '16

运行此解决方案时,我收到“正在构建文件列表...完成\ n发送了X个字节,收到了Y个字节,Z个字节/秒的总大小是A,加速是B”(其中,我用XYZAB代替数字)。这是否意味着一切都一样?既然没有提到更具体的内容?在此先感谢
Scott H

为了回答我自己的问题,我尝试了为每个文件添加不同的文件,并且看起来输出中没有提到的特定文件/目录意味着它们都是相同的。
Scott H

18

与ls答案类似,但是如果您安装树,则可以

tree dir1 > out1
tree dir2 > out2
diff out1 out2

7
还是避免使用tmpfile,diff <( tree dir1 ) <( tree dir2 )
Joel Mellon

1
我建议使用带有i标志的树,该标志不会显示树线(tree -i dir1,等)。如果目录结构在一个地方不同,则匹配的其他文件|在树输出中可能会有更多或更少的符号,即使文件路径相同,diff也会捕获这些行。
askewchan

2
diff <(tree -i dir1)<(tree -i dir2)是最好的答案。我很想拒绝所有建议diff或rsync的答案,因为该问题明确指出不要读取文件内容。注意:建议使用两个管道需要仔细使用支架之间的空间,请严格按照示例进行操作。例如,在备份后比较两个20G卷,树的答案大约花费了5秒钟。其他人花了20多分钟。
杰森·摩根

3

我只是在寻找解决此问题的方法。我最喜欢的解决方案是:

comm <(ls DIR1) <(ls DIR2)

它为您提供3列:1-仅在DIR1中的文件,2-仅在DIR2中的文件,3-仅在DIR3中的文件有关更多详细信息,请参阅此博客文章。


DIR3指定在哪里?我所看到的是DIR1DIR2
迈克尔·多斯特

我试了一下,(从我可以告诉)输出是:所有的文件只能在DIR1第1列,只有在所有文件DIR2中的第2列,和所有文件通过共享双方第3列。这很有用,但是您知道如何去除第3列并仅保留差异吗?我要整理的文件很多,而且大多数文件是相同的。我不需要看看有什么相同。
Michael Dorst,2013年

1
另外,我发现comm <(ls DIR1) <(ls DIR2)递归无效。为此我用comm <(ls -R1 DIR1) <(ls -R1 DIR2)ls -R递归地浏览目录,并且ls -1(请注意那是一个,而不是L)使ls每行仅打印一个文件名。
Michael Dorst

@Michael :(comm -3请参阅参考资料man comm)。
Zaz 2014年

2
ls > dir1.txt

ls > dir2.txt

然后只比较两个列表。


OP似乎希望获得路径的层次结构。这将比较当前目录中的所有文件。他只想要目录是有争议的,但有可能的。他可能想要文件名而不是文件内容。
直觉

@intuited-你是对的。我看错了
MDMarra

2

这是最佳解决方案

diff --brief -r dir1 dir2

--brief开关仅报告文件是否不同,而不报告差异的详细信息。


1
OP已-q在问题中存在,这是的别名--brief。该答案未提供任何新信息。
2013年

1
OP不需要文件内容比较。But it's really slow because it's comparing files too.
乔尔·梅隆2014年

1

使用“ diff -qr”获取不同的文件,然后使用grep过滤掉文件比较,以便仅获取仅在目录之一中的文件名。

diff -qr dir1 dir2 | grep -v "Files.*differ" 

1

这适用于我的特殊需求,即在预期匹配的树中查找丢失的文件。

diff <( cd dir1; find * |sort ) <(cd dir2; find * | sort)

-3

我认为只有rsync是userfull。为什么?

diff仅对保留文件和目录的结构有用。当我们使用符号链接时,Diff没有给出足够的退出代码。在这种情况下,即使src和dst相同(时间,大小,名称,时间戳,指向软链接等),diff也可以返回2个退出代码。

dir,即使src和dst上的目录内容相同,文件系统也不保证文件顺序。也许您应该通过排序对ls输出进行过滤。但是纯ls仅显示节点名称。

也许包括diff,cmp,test -X的节点类型的脚本将很有用,但请记住许多test / cmp运行造成的过载。该脚本将非常慢。

像往常一样,如果要获取简单的信息“目录是否相同”,则应将rsync与-n(干)选项一起使用。如果要查找不同之处,请使用diff命令。


我想知道为什么有缺点?
Znik
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.