比较两个目录的内容

我有两个目录应该包含相同的文件,并具有相同的目录结构。

我认为其中一个目录中缺少某些东西。

使用bash shell,有没有办法比较我的目录,看看其中一个是否丢失了另一个目录中的文件?

进行此比较的一个好方法是使用find with md5sum ,然后使用diff

使用find列出目录中的所有文件,然后计算每个文件的md5哈希,并将其按文件名排序到文件:

 find /dir1/ -type f -exec md5sum {} + | sort -k 2 > dir1.txt 

对另一个目录执行相同的过程:

 find /dir2/ -type f -exec md5sum {} + | sort -k 2 > dir2.txt 

然后将结果两个文件与diff

 diff -u dir1.txt dir2.txt 

或者作为使用进程替换的单个命令:

 diff <(find /dir1/ -type f -exec md5sum {} + | sort -k 2) <(find /dir2/ -type f -exec md5sum {} + | sort -k 2) 

当要比较的两个目录不在同一台机器中并且您需要确保两个目录中的文件相同时,此策略非常有用。

另一个好方法是使用Git的diff命令(当文件具有不同的权限时可能会导致问题 - >然后输出中列出了每个文件):

 git diff --no-index dir1/ dir2/ 

您可以像使用文件一样使用diff命令:

 diff   

如果要查看子文件夹和文件,也可以使用-r选项:

 diff -r   

通过你不使用bash,你可以使用diff与--brief--recursive --brief

 $ diff -rq dir1 dir2 Only in dir2: file2 Only in dir1: file1 

man diff包括两个选项:

-q , – --brief
仅在文件不同时报告

-r , – --recursive
递归地比较找到的所有子目录

这是另一种方法,只比较文件名,而不是它们的内容:

 diff <(cd folder1 && find . | sort) <(cd folder2 && find . | sort) 

这是列出丢失文件的简单方法,但当然它不会检测具有相同名称但内容不同的文件!

(我个人使用自己的diffdirs脚本,但这是一个更大的库的一部分。)

如果要使每个文件都可扩展和可折叠,可以将diff -r的输出传递给Vim。

首先让我们给Vim一个折叠规则:

 mkdir -p ~/.vim/ftplugin echo "set foldexpr=getline(v:lnum)=~'^diff.*'?'>1':1 foldmethod=expr fdc=2" >> ~/.vim/ftplugin/diff.vim 

现在只是:

 diff -r dir1 dir2 | vim - 

您可以点击zozc来打开和关闭折叠。 要退出Vim,请点击:q

在python中实现相当简单的任务:

 python -c 'import os,sys;d1=os.listdir(sys.argv[1]);d2=os.listdir(sys.argv[2]);d1.sort();d2.sort();x="SAME" if d1 == d2 else "DIFF";print x' DIR1 DIR2 

替换DIR1DIR2实际值。

这是样本运行:

 $ python -c 'import os,sys;d1=os.listdir(sys.argv[1]);d2=os.listdir(sys.argv[2]);d1.sort();d2.sort();x="SAME" if d1 == d2 else "DIFF";print x' Desktop/ Desktop SAME $ python -c 'import os,sys;d1=os.listdir(sys.argv[1]);d2=os.listdir(sys.argv[2]);d1.sort();d2.sort();x="SAME" if d1 == d2 else "DIFF";print x' Desktop/ Pictures/ DIFF 

为了便于阅读,这里是一个实际的脚本而不是单行:

 #!/usr/bin/env python import os, sys d1 = os.listdir(sys.argv[1]) d2 = os.listdir(sys.argv[2]) d1.sort() d2.sort() if d1 == d2: print("SAME") else: print("DIFF") 

受Sergiy的回复启发,我编写了自己的Python脚本来比较两个目录。

与许多其他解决方案不同,它不会比较文件的内容。 此外,它不会进入其中一个目录中缺少的子目录。 因此输出非常简洁,脚本可以快速处理大型目录。

 #!/usr/bin/env python3 import os, sys def compare_dirs(d1: "old directory name", d2: "new directory name"): def print_local(a, msg): print('DIR ' if a[2] else 'FILE', a[1], msg) # ensure validity for d in [d1,d2]: if not os.path.isdir(d): raise ValueError("not a directory: " + d) # get relative path l1 = [(x,os.path.join(d1,x)) for x in os.listdir(d1)] l2 = [(x,os.path.join(d2,x)) for x in os.listdir(d2)] # determine type: directory or file? l1 = sorted([(x,y,os.path.isdir(y)) for x,y in l1]) l2 = sorted([(x,y,os.path.isdir(y)) for x,y in l2]) i1 = i2 = 0 common_dirs = [] while i1l2[i2][0]: print_local(l2[i2],'added') i2 += 1 while i1 

如果将其保存到名为compare_dirs.py的文件中,则可以使用Python3.x运行它:

 python3 compare_dirs.py dir1 dir2 

样本输出:

 user@laptop:~$ python3 compare_dirs.py old/ new/ DIR old/out/flavor-domino removed DIR new/out/flavor-maxim2 added DIR old/target/vendor/flavor-domino removed DIR new/target/vendor/flavor-maxim2 added FILE old/tmp/.kconfig-flavor_domino removed FILE new/tmp/.kconfig-flavor_maxim2 added DIR new/tools/tools/LiveSuit_For_Linux64 added 

PS如果你需要比较文件大小和文件哈希值以进行潜在的更改,我在这里发布了一个更新的脚本: https : //gist.github.com/amakukha/f489cbde2afd32817f8e866cf4abe779

也许一个选项是运行rsync两次

 rsync -r -n -t -v --progress -c -s /dir1/ /dir2/ 

使用上一行,您将获得dir1中的文件,并且dir2中的文件不同(或缺失)。 还有不同日期的文件夹。

 rsync -r -n -t -v --progress -c -s /dir2/ /dir1/ 

dir2也一样

 #from the rsync --help : -r, --recursive recurse into directories -n, --dry-run perform a trial run with no changes made -t, --times preserve modification times -v, --verbose increase verbosity --progress show progress during transfer -c, --checksum skip based on checksum, not mod-time & size -s, --protect-args no space-splitting; only wildcard special-chars 

您可以删除-n选项以进行更改。 那就是将文件列表复制到第二个文件夹。

如果你这样做,也许一个很好的选择是使用-u,以避免覆盖较新的文件。

 -u, --update skip files that are newer on the receiver 

我将在此列表中添加一段时间以前我写过的NodeJs替代方案。

DIR-比较

 npm install dir-compare -g dircompare dir1 dir2