给定两个目录树,如何找出哪些文件内容不同?

978

如果我想找出两个目录树之间的差异,我通常只需执行:

diff -r dir1/ dir2/

这段代码输出的是对应文件之间的确切差异。我只想获取内容不同的对应文件列表。我认为只需通过传递命令行选项给diff就可以实现,但手册上没有找到相关信息。

有什么建议吗?


5
如何比较Linux中两个目录之间的差异? - Dan Dascalescu
1
关于其中一个目录,如何获取另一个目录中仅存在的文件/目录? - Sandeepan Nath
在Unix操作系统上使用dircmp命令(不是Linux)。 - roblogic
10个回答

1409

试试:

diff --brief --recursive dir1/ dir2/

或者,使用短标志-qr

diff -qr dir1/ dir2/

如果你想查看可能不存在于任一目录中的文件的差异:

diff --brief --recursive --new-file dir1/ dir2/  # with long options
diff -qrN dir1/ dir2/                            # with short flag aliases

29
好的。但是更短的方式是 diff -qr dir1/ dir2/,而我对此进行了扩展,变成了 diff -qr dir1/ dir2/ | grep ' differ' - sobi3ch
3
@skv 不完全是原始问题所问的,但更新答案以适应这个问题。 - Mark Loeser
12
@MikeMaxwell需要使用--brief-brief会被解释为-b -r -i -e -f,也就是一组标志而不是单个选项。 - daboross
3
哇,我已经使用Unix/Linux很长时间了,但我从来没有意识到“--”和“-”之间存在区别。(我认为在我刚开始使用时,“--”并不存在)感谢您的解释! - Mike Maxwell
10
根据man ps-选项被称为“UNIX选项”,而--选项被称为“GNU长选项”。如果程序使用任何选项,则应使每个程序都接受长选项,因为这样做只需要很少的额外工作,有助于初学者记住如何使用该程序。 - Elijah Lynn
显示剩余7条评论

315

我使用的命令是:

diff -qr dir1/ dir2/

这与 Mark 的答案完全相同 :) 但他的答案让我感到不安,因为它使用不同的 类型 标志,让我不得不看两次。使用 Mark 更详细的标志,它将是:

diff  --brief --recursive dir1/ dir2/

很抱歉在其他答案已经完全可接受的情况下还发表了自己的看法。我控制不住自己...正在努力变得不那么追求完美。


13
将仅仅有不同口味的不同答案放在一起,这样做有意义吗?在我看来不是。将两个答案合并成一个连贯的答案,这样做有意义吗?是的!;) - sobi3ch
1
只是一个问题:q代表什么?它是某个缩写吗?我找不到任何q背后的逻辑... - kramer65
3
@kramer65 - 它与"--brief"相同,但我猜你想知道为什么要用q?也许是因为快速(quick)的缩写?根据man手册,“-b”已被“忽略空格变化”所占用。 - FPC
@sobi3ch 你是对的,我再次道歉。为了辩护自己,我当时认为我没有编辑其他答案的能力。 - FPC
9
我相信 q 是指“quiet”,通常意味着较少冗长的输出。 - Gogeta70
显示剩余2条评论

156

我喜欢使用 git diff --no-index dir1/ dir2/ ,因为它可以显示颜色差异(如果您在git配置中设置了该选项),并且使用“less”将所有差异显示在一个长的分页输出中。


47
太好了。谁会想到git可以比较任意目录,而不仅仅是仓库与其文件之间的差异? - Dan Dascalescu
3
这里非常有用的 Perl 脚本 colordiff,可以与 SVN 和普通差异比较工具一起使用。 - Felipe Alvarez
8
如果你像我一样把两个目录当作单独的Git项目/仓库进行比较,那么你需要在https://dev59.com/yHI-5IYBdhLWcg3wkJIA#1792477 上加上--no-index。我已经更新了@alan-porter的答案。 - sobi3ch
1
我喜欢这个命令,如果你在命令行中添加 --name-status ,它将只显示带有“M/A/D”标志的文件名列表,表示修改/添加/删除状态。 - gzh
1
两个目录都包含.git文件夹,我该如何在比较中排除它? - Silidrone

58

使用 rsync

rsync --dry-run --recursive --delete --links --checksum --verbose /dir1/ /dir2/ > dirdiff_2.txt
# or same in short
rsync -nrlcv --delete /dir{1,2}/ > dirdiff_2.txt

或者,使用 diff 命令:

diff --brief --recursive --no-dereference --new-file --no-ignore-file-name-case /dir1 /dir2 > dirdiff_1.txt
# or same in short
diff -qrN --no-dereference --no-ignore-file-name-case /dir{1,2} > dirdiff_1.txt

它们在功能上是等效的,但性能可能会因以下原因而有所不同:

  • 如果目录位于同一驱动器上,则rsync更快。
  • 如果目录位于两个不同的驱动器上,则diff更快。

这是因为diff在并行处理时几乎平均地使两个目录负载,并最大限度地利用了两个驱动器的负载。 rsync在实际比较之前按大块计算校验和。这将大块I / O操作分组,并在单个驱动器上进行更有效的处理。


5
rsync 不仅对于单个磁盘上的文件更快,而且还能够比较子目录中的文件。例如,使用命令 rsync --options /usr /bin /var /sbin /lib /old_root 可以有效地比较当前根目录 /(通过指定其中的所有子目录)和 /old_root(包含了例如 / 的某个早期备份),这是 diff -r 无法做到的。如果你假设大小、权限和时间戳相同的文件可能没有变化,那么省略 --checksum 将为你提供极快(但不全面)的检查哪些文件可能已经更改的结果。 - Matija Nalis
3
--delete 的作用是删除目标目录中存在但在源目录中不存在(或已不再存在)的文件。 - Thomas Munk
7
使用“--dry-run”标志时,实际上没有任何文件被删除,rsync只会打印出在dir1中但不在dir2中的文件。 - mata
22
建议始终将 --dry-run 放在第一位,以免意外遗漏它。 - Dave Rager
3
如果您需要比较通过ssh访问的本地和远程目录,那么“rsync”解决方案非常有用。 - Francesco Frassinelli
显示剩余4条评论

41

Meld是一款用于比较两个目录的绝佳工具:

meld dir1/ dir2/

Meld有许多用于比较文件或目录的选项。如果两个文件不同,很容易进入文件比较模式并查看确切的差异。


2
不错。我已经编写了一个简单的Perl脚本来执行树比较,但是我遇到了一些限制。这似乎是解决问题的方法。 - David Tonhofer
唯一的问题是它不适合脚本编写,因为它是一个图形应用程序。但如果你不介意 GUI 的话,它还是很好用的!谢谢。 - DeanM
1
我发现如果用于大目录,meld 的性能会变得非常低下。有什么其他工具可以更好地处理大目录吗? - Popup
@Popup,我不知道有没有这样的功能。但你可以使用以下命令查找不同的文件名:find dir1 dir2 | cut -d/ -f2- | sort | uniq --unique - Alexander
2
@Alexander - 在这种情况下,我发现使用bash进程替换meld <(find dir1 -ls ) <(find dir2 -ls)效果非常好。(zsh的=(command)效果更好。) - Popup
显示剩余2条评论

12

频道成员'billings'(在freenode/#centos中很有名)与我分享了他的方法:

diff -Naur dir1/ dir2

包括最后的目录斜杠(/)并不重要。

另外,在一些较旧/服务器版本的diff中,似乎没有可用的-u选项。

差异在于:

# diff -Nar /tmp/dir1 /tmp/dir2/
diff -Nar /tmp/dir1/file /tmp/dir2/file
28a29
> TEST

# diff -qr /tmp/dir1/ /tmp/dir2/
Files /tmp/dir1/file and /tmp/dir2/file differ

2
那么这就是--new-file/-N,它使diff将缺失的文件视为空文件,以及--text/-a,它导致diff将所有二进制输入视为文本。我看不到这种特定用例的优点。 - phk

5

使用此命令查找差异:

diff -qr dir1/ dir2/

-r 将会递归比较所有子目录 -q 告诉 diff 仅在文件不同的情况下报告。

diff  --brief dir1/ dir2/

--brief选项将显示不存在于目录中的文件。

或者

我们也可以使用Meld,它会在图形窗口中显示文件差异,更加易于查找。

meld  dir1/ dir2/

4
--brief-q 是相同的选项。您的陈述使它们听起来不同,但事实上它们是相同的。 - Elijah Lynn

4

Diffoscope 是一款非常好用的基于命令行的目录比较工具。

我特别喜欢它能够将比较结果 输出到 文件中:

它可以递归地解压多种类型的存档文件,并将各种二进制格式转换为更易读的形式以进行比较。它可以轻松比较两个tarball、ISO映像或PDF文件。

它不仅会告诉你哪些文件不同,还会告译它们如何不同。


2
您也可以使用Rsync和find。对于find:
find $FOLDER -type f | cut -d/ -f2- | sort > /tmp/file_list_$FOLDER

但是,具有相同名称且位于相同子文件夹中但内容不同的文件将不会显示在列表中。

如果您喜欢图形用户界面,可以查看Meld,这是@Alexander提到的。它在Windows和Linux上都很好用。


2

报告dirA和dirB之间的差异,同时更新/同步:

rsync -auv <dirA> <dirB>

1
虽然它可能有效,但使用rsync会增加一层复杂性,因为现在您需要该依赖项。在我看来,这是一个不错的附带效果,但它使用的不仅仅是Linux。 - Lomefin
1
@Lomefin 我不明白为什么rsyncdiff更不Linux。@Kickaha 在执行该命令之前,你肯定需要对目标目录进行备份。 - Mogens TrasherDK

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接