对比两个目录,找出有区别的文件【仅文件名,不是内容】

比如:在一个目录下有,在另一个目录下没有都算在内

diff仅输出文件名

我正在寻找运行Linux命令,它将递归地比较两个目录并输出 仅 不同的文件名。这包括一个目录中存在的任何内容而不是另一个目录中的任何内容,反之亦然,以及文本差异。

回答1:

从diff手册页:

-q仅报告文件是否不同,而不是差异的细节。
-r比较目录时,递归比较找到的所有子目录。

示例命令:

diff -qr dir1 dir2

示例输出(取决于区域设置):

$ ls dir1 dir2
dir1:
same-file  different  only-1

dir2:
same-file  different  only-2
$ diff -qr dir1 dir2
Files dir1/different and dir2/different differ
Only in dir1: only-1
Only in dir2: only-2

回答2:
您也可以使用rsync
rsync -rv --size-only --dry-run /my/source/ /my/dest/ > diff.out

回答3:这个重点

如果要获取仅在一个目录而不是其子目录中的文件列表,并且只获取其文件名:

diff -q /dir1 /dir2 | grep /dir1 | grep -E "^Only in*" | sed -n 's/[^:]*: //p'

如果要递归列出与其完整路径不同的所有文件和目录:

diff -rq /dir1 /dir2 | grep -E "^Only in /dir1*" | sed -n 's/://p' | awk '{print $3"/"$4}'

这样,您可以对所有文件应用不同的命令。

例如,我可以删除dir1中的所有文件和目录,但不删除dir2:

diff -rq /dir1 /dir2 | grep -E "^Only in /dir1*" | sed -n 's/://p' | awk '{print $3"/"$4}' xargs -I {} rm -r {}

运行diff -qr old/ new/的方法有一个主要缺点:它可能会丢失新创建的目录中的文件。例如。在下面的示例中,文件data/pages/playground/playground.txt不在diff -qr old/ new/的输出中,而目录data/pages/playground/是(在浏览器中搜索 playground.txt 以快速比较)。我还发布了以下解决方案 在Unix和Linux Stack Exchange上 ,但我也会在这里复制它:

要以编程方式创建新文件或已修改文件的列表,我可以提出的最佳解决方案是使用 rsync , sort ,和 uniq :

(rsync -rcn --out-format="%n" old/ new/ && rsync -rcn --out-format="%n" new/ old/) | sort | uniq

让我用这个例子来解释一下:我们想要比较两个dokuwiki版本,看看哪些文件被更改,哪些文件是新创建的。

我们用wget获取tars并将它们提取到old/new/目录中:

wget http://download.dokuwiki.org/src/dokuwiki/dokuwiki-2014-09-29d.tgz
wget http://download.dokuwiki.org/src/dokuwiki/dokuwiki-2014-09-29.tgz
mkdir old && tar xzf dokuwiki-2014-09-29.tgz -C old --strip-components=1
mkdir new && tar xzf dokuwiki-2014-09-29d.tgz -C new --strip-components=1

以一种方式运行rsync可能会错过新创建的文件,因为rsync和diff的比较显示在此处:

rsync -rcn --out-format="%n" old/ new/

产生以下输出:

VERSION
doku.php
conf/mime.conf
inc/auth.php
inc/lang/no/lang.php
lib/plugins/acl/remote.php
lib/plugins/authplain/auth.php
lib/plugins/usermanager/admin.php

仅在一个方向上运行rsync错过了新创建的文件,反过来会错过已删除的文件,比较diff的输出:

diff -qr old/ new/

产生以下输出:

Files old/VERSION and new/VERSION differ
Files old/conf/mime.conf and new/conf/mime.conf differ
Only in new/data/pages: playground
Files old/doku.php and new/doku.php differ
Files old/inc/auth.php and new/inc/auth.php differ
Files old/inc/lang/no/lang.php and new/inc/lang/no/lang.php differ
Files old/lib/plugins/acl/remote.php and new/lib/plugins/acl/remote.php differ
Files old/lib/plugins/authplain/auth.php and new/lib/plugins/authplain/auth.php differ
Files old/lib/plugins/usermanager/admin.php and new/lib/plugins/usermanager/admin.php differ

两种方式运行rsync并对输出进行排序以删除重复项显示最初错过了目录data/pages/playground/和文件data/pages/playground/playground.txt

(rsync -rcn --out-format="%n" old/ new/ && rsync -rcn --out-format="%n" new/ old/) | sort | uniq

产生以下输出:

VERSION
conf/mime.conf
data/pages/playground/
data/pages/playground/playground.txt
doku.php
inc/auth.php
inc/lang/no/lang.php
lib/plugins/acl/remote.php
lib/plugins/authplain/auth.php
lib/plugins/usermanager/admin.php

rsync使用theses参数运行:

  • -r“递归到目录”,
  • -c还比较相同大小的文件,只“基于校验和跳过,而不是模态时间和大小”,
  • -n“执行试运行而不进行任何更改”,以及
  • --out-format="%n"为“使用指定的FORMAT输出更新”,此处仅为“%n”,仅用于文件名

两个方向上rsync的输出(文件列表)被组合并使用sort进行排序,然后通过使用uniq删除所有重复项来压缩此排序列表。

 8
2015年3月24日iolsmit

在我的linux系统上获取 只是 文件名

diff -q /dir1 /dir2|cut -f2 -d' '
 

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

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多分钟。
— 杰森·摩根

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

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年

ls > dir1.txt

ls > dir2.txt

然后只比较两个列表。

 

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

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

这是最佳解决方案

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年

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

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

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

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命令。

 

 
 
 
 

posted on 2020-07-20 17:22  ZhYQ_note  阅读(3003)  评论(0编辑  收藏  举报

导航