我认为这些目录之一中缺少某些内容。
使用bash shell,有没有一种方法可以比较我的目录,看看其中一个是否丢失了另一个目录中存在的文件?
#1 楼
进行比较的一个好方法是先将find
与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)
如果您只想查看更改:
diff <(find /dir1/ -type f -exec md5sum {} + | sort -k 2 | cut -f1 -d" ") <(find /dir2/ -type f -exec md5sum {} + | sort -k 2 | cut -f1 -d" ")
cut命令仅打印要与diff比较的哈希(第一个字段)。否则,即使散列相同,diff也会打印每行,因为即使散列相同,目录路径也会不同。
但是您不知道哪个文件已更改...
为此,您可以尝试使用
diff <(find /dir1/ -type f -exec md5sum {} + | sort -k 2 | sed 's/ .*\// /') <(find /dir2/ -type f -exec md5sum {} + | sort -k 2 | sed 's/ .*\// /')
要比较的两个目录不在同一台机器上,并且您需要确保两个目录中的文件相等。
进行此工作的另一个好方法是使用Git的
diff
命令(可能会引起问题)如果文件具有不同的权限->每个文件都会在输出中列出): git diff --no-index dir1/ dir2/
评论
如果没有额外的排序步骤,这将不起作用,因为在两个目录之间,查找将列出文件的顺序通常会有所不同。
– Faheem Mitha
17年8月30日在10:22
可以使用askubuntu.com/a/662383/15729中描述的方法对文件进行排序。
– Faheem Mitha
17年8月30日在10:48
我收到错误消息``找到:md5sum:没有这样的文件或目录
–侯曼
17-10-3在13:14
@Houman我不知道您使用的是什么Linux Distro,但是也许您需要安装一个提供de md5sum的软件包。在Fedora 26中,您可以使用以下命令进行安装:#dnf install coreutils
– Adail Junior
17-10-4在19:05
另外,在git diff --no-index中添加--stat或--name-status可能是最容易理解的差异摘要。
–迈克尔
19/12/4在22:59
#2 楼
您可以像使用文件一样使用diff
命令:diff <directory1> <directory2>
如果还要查看子文件夹和-files,可以使用
-r
选项: diff -r <directory1> <directory2>
评论
不知道diff也适用于目录(man diff确认了),但这不会递归检查子目录中子目录的更改。
–jobin
2014年2月16日在17:04
@Jobin这很奇怪...对我来说,它确实有效。
– Alex R.
2014年2月16日在17:07
我有这样的东西:a / b / c / d / a,x / b / c / d / b。看看diff x给你的。
–jobin
2014-02-16 17:09
您必须使用-r选项。那(diff -r a x)给我:仅在a / b / c / d中:a。仅在x / b / c / d中:b。
– Alex R.
14年2月16日在17:11
diff告诉我INTO文件的区别,但如果目录包含另一个文件不包含的文件,则不告诉我!我不需要知道文件中的差异,但是也不需要知道文件是否存在于目录中,而不存在于另一个目录中
– AndreaNobili
14年2月16日在17:17
#3 楼
通过不使用bash,可以使用diff与--brief
和--recursive
进行比较:$ diff -rq dir1 dir2
Only in dir2: file2
Only in dir1: file1
man diff
包括两个选项:-q
和--brief
仅在文件不同时报告
-r
和--recursive
递归比较找到的所有子目录
#4 楼
也许一个选项是运行rsync两次:rsync -rtOvcs --progress -n /dir1/ /dir2/
与上一行一样,您将获得dir1中的文件,而dir2中的文件不同(或丢失)。
rsync -rtOvcs --progress -n /dir2/ /dir1/
dir2相同
#from the rsync --help :
-n, --dry-run perform a trial run with no changes made
-r, --recursive recurse into directories
-t, --times preserve modification times
-O, --omit-dir-times omit directories from --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
单线:
rsync -rtOvcsu --progress -n /dir1/ /dir2/ && rsync -rtOvcsu --progress -n /dir2/ /dir1/
#5 楼
这是一种选择,仅比较文件名,而不比较它们的内容:diff <(cd folder1 && find . | sort) <(cd folder2 && find . | sort)
这是列出丢失文件的简便方法,但是当然不会检测到名称相同但内容不同的文件!
(我个人使用自己的
diffdirs
脚本,但这是较大的库的一部分。)评论
您最好使用进程替换,而不是临时文件...
–mniip
2014年2月16日在18:03
请注意,这不支持带有某些特殊字符的文件名,在这种情况下,您可能要使用零分隔符,而AFAIK diff到目前为止还不支持。但是自git.savannah.gnu.org/cgit/coreutils.git/commit/以来,就有支持它的通讯。因此,一旦您附近遇到coreutils,您可以执行comm -z <(cd folder1 && find -print0 | | sort)<(cd folder2 && find -print0 | sort -z)(可能需要使用--output-delimiterparameter和其他工具将其输出进一步转换为所需的格式)。
–phk
16 Mar 5 '16 at 21:52
#6 楼
我想建议一个我刚刚发现的好工具:MELD。它可以正常工作,并且您可以在基于Linux的系统上使用
diff
命令执行的所有操作都可以在其中复制并带有漂亮的图形界面!例如目录比较简单明了:
文件比较也更容易了:实例Git),并且可以用作合并工具。请参阅其网站上的完整文档。
#7 楼
在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
替换
DIR1
和DIR2
的实际值。 此处的示例运行:
$ 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")
评论
注意,os.listdir没有给出任何特定的顺序。因此,列表可能具有相同的事物,但顺序不同,因此比较将失败。
–muru
16年11月14日在6:15
@muru好点,我将包括对它的排序
– Sergiy Kolodyazhnyy
16年11月14日在6:17
#8 楼
受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 i1<len(l1) and i2<len(l2):
if l1[i1][0] == l2[i2][0]: # same name
if l1[i1][2] == l2[i2][2]: # same type
if l1[i1][2]: # remember this folder for recursion
common_dirs.append((l1[i1][1], l2[i2][1]))
else:
print_local(l1[i1],'type changed')
i1 += 1
i2 += 1
elif l1[i1][0]<l2[i2][0]:
print_local(l1[i1],'removed')
i1 += 1
elif l1[i1][0]>l2[i2][0]:
print_local(l2[i2],'added')
i2 += 1
while i1<len(l1):
print_local(l1[i1],'removed')
i1 += 1
while i2<len(l2):
print_local(l2[i2],'added')
i2 += 1
# compare subfolders recursively
for sd1,sd2 in common_dirs:
compare_dirs(sd1, sd2)
if __name__=="__main__":
compare_dirs(sys.argv[1], sys.argv[2])
如果将其保存到名为
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
评论
谢谢,我添加了一个可选的第三个参数正则表达式来跳过/忽略gist.github.com/mscalora/e86e2bbfd3c24a7c1784f3d692b1c684使我需要的内容如下:cmpdirs dir1 dir2'/\.git/'
–迈克
18年2月18日在22:15
#9 楼
如果要使每个文件都可扩展和可折叠,则可以将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 - -R
您可以按
zo
和zc
打开和关闭折叠。要摆脱Vim,请点击:q<Enter>
,但
-R
是可选的,但我发现它与-
一起使用非常有用,因为它可以阻止Vim在退出时困扰您以保存缓冲区。#10 楼
如果您有成千上万个文件,那么Adail Junior的好答案可能会在时间执行上出现问题!所以这是另一种方法。假设您要比较文件夹A的所有文件名和文件夹B的所有文件名。
步骤1,将cd转到文件夹A并执行:
find . | sort -k 2 > listA.txt
步骤2,将cd放入文件夹B并执行以下操作:
find . | sort -k 2 > listB.txt
步骤3,获取listA.txt的差异和listB.txt
我尝试在包含50万个txt文件的文件夹中,并且在不到30秒的时间内,屏幕上显示了差异,而计算md5sum和然后进行管道化然后附加可能非常非常耗时。还请注意,最初的问题是要求比较文件名(而不是它们的内容!),并检查所比较的文件夹之间是否缺少文件!谢谢
#11 楼
我将在一段时间前添加的NodeJs替代品添加到此列表中。dir-compare
npm install dir-compare -g
dircompare dir1 dir2
#12 楼
您可以使用此工具:https://github.com/jfabaf/comparefolders/
我几年前开发了它,因为遇到了同样的问题。
它比较文件的MD5,所以与文件名无关。
#13 楼
如前所述,您还可以使用comm命令,例如这样:comm -3 <(ls -1 dir1) <(ls -1 dir2)
比较两个目录的内容,仅显示2列,每个列都有该目录唯一的文件。
评论
bash --version的输出是什么?类似但更具体:stackoverflow.com/questions/16787916/…