如何计算目录的md5校验和?


133

我需要为*.py放置在目录和所有子目录下的特定类型(例如)的所有文件计算md5校验摘要。

最好的方法是什么?

编辑:提出的解决方案非常好,但这并不是我所需要的。我正在寻找一种解决方案,以获取单个摘要校验和,该校验和将唯一标识整个目录-包括其所有子目录的内容。


看看这个这个了更详细的解释。
luvieere

3
对我来说似乎是一个超级用户问题。
Noldorin

8
请注意,校验和不会唯一标识任何内容。
Hosam Aly

1
为什么要有两个可能唯一要标识的“相同”目录树?文件创建/修改/访问时间重要吗?您真正需要版本控制吗?
jmucchiello,2009年

在我的情况下,真正重要的是整个目录树内容的相似性,这意味着AFAIK:1)目录树下任何文件的内容都没有更改2)没有新文件添加到目录树3)没有文件被删除
victorz

Answers:


152
find /path/to/dir/ -type f -name "*.py" -exec md5sum {} + | awk '{print $1}' | sort | md5sum

find命令列出所有以.py结尾的文件。为每个.py文件计算md5sum。awk用于选择md5sums(忽略文件名,文件名可能不是唯一的)。md5sums被排序。然后返回此排序列表的md5sum。

我已经通过复制测试目录对此进行了测试:

rsync -a ~/pybin/ ~/pybin2/

我重命名了〜/ pybin2中的某些文件。

find...md5sum命令为两个目录返回相同的输出。

2bcf49a4d19ef9abd284311108d626f1  -

24
请注意,如果文件被重命名,将生成相同的校验和。因此,如果您将文件布局视为签名的一部分,那么这实际上不适合“将唯一地识别整个目录的校验和”。
Valentin Milea 2012年

1
您可以稍微更改命令行以在每个文件校验和的前面加上文件名(甚至更好的是文件从/ path / to / dir /的相对路径),以便在最终校验和中将其考虑在内。
Michael Zilbermann

4
@ zim2001:是的,可以更改它,但是据我了解的问题(特别是由于OP在问题下的注释),OP希望如果文件内容相同而不考虑文件名或文件名,则任何两个目录都应视为相等甚至相对路径。
unutbu 2013年

@unutbu:我知道;我正在回应Valentin Milea的前一个笔记。
Michael Zilbermann

awk ...如果您将布局视为签名的一部分,则@ValentinMilea仅删除该部分。
segfault

166

快速创建tar存档文件,并将其传输到md5sum

tar c dir | md5sum

这将产生一个md5sum,它对于您的文件和子目录设置应该是唯一的。没有在磁盘上创建文件。


25
@CharlesB具有单个校验和,您永远不会知道哪个文件是不同的。问题是关于目录的单个校验和。
霍肯2012年

17
ls -alR dir | md5sum。最好不进行压缩,而只是读取。这是唯一的,因为内容包含文件的修改时间和大小;)
Sid

14
@ Daps0l-我的命令中没有压缩。您需要z为gzip或jbzip2添加。我都没做
ire_and_curses 2012年

7
请注意,这样做将文件和其他内容的时间戳集成到校验和计算中,而不仅是文件的内容
Michael Zilbermann

10
这很可爱,但实际上并不起作用。不能保证tar两次或在两台不同的计算机上复制相同的文件集会产生相同的准确结果。
fletom

46

ire_and_curses的使用建议tar c <dir>存在一些问题:

  • tar按照目录条目在文件系统中存储的顺序进行处理,因此无法更改此顺序。如果您在不同位置具有“相同”目录,这实际上可以产生完全不同的结果,而且我不知道解决此问题的方法(tar无法按特定顺序对输入文件进行“排序”)。
  • 我通常关心的是groupid和ownerid编号是否相同,而不一定是group / owner的字符串表示形式是否相同。这与例如rsync -a --delete所做的工作是一致的:它几乎同步了所有内容(减去xattrs和acls),但是将根据所有者和组的ID同步,而不是基于字符串表示。因此,如果您同步到不一定具有相同用户/组的其他系统,则应将--numeric-owner标志添加到tar
  • tar将包含您要检查的目录的文件名,这是需要注意的。

只要没有解决第一个问题的方法(或者除非您确定它不会影响您),否则我不会使用这种方法。

find上面提出的基于基础的解决方案也不是一件好事,因为它们仅包括文件,而不包括目录,如果校验和应牢记空目录,这将成为一个问题。

最后,大多数建议的解决方案并不是一致排序的,因为排序规则在系统之间可能有所不同。

这是我想出的解决方案:

dir=<mydir>; (find "$dir" -type f -exec md5sum {} +; find "$dir" -type d) | LC_ALL=C sort | md5sum

关于此解决方案的注意事项:

  • LC_ALL=C是为了确保整个系统的可靠排序顺序
  • 这不能区分目录“ \ nwithanewline”和两个目录“ named”和“ withanewline”,但是这种可能性似乎很小。通常用一个-print0标志来解决此问题,find但是由于这里还有其他问题,我只能看到使该命令变得更复杂而不值得的解决方案。

PS:我的系统之一使用了一个有限的busybox find,它不支持-exec也不-print0标记,并且还附加了“ /”来表示目录,而findutils find似乎没有,所以对于这台机器,我需要运行:

dir=<mydir>; (find "$dir" -type f | while read f; do md5sum "$f"; done; find "$dir" -type d | sed 's#/$##') | LC_ALL=C sort | md5sum

幸运的是,我没有名称中包含换行符的文件/目录,因此在该系统上这不是问题。


1
+1:非常有趣!您是说不同文件系统类型之间或同一文件系统内的顺序可能不同吗?
ire_and_curses 2011年

2
都。它仅取决于每个目录中目录条目的顺序。AFAIK目录条目(在文件系统中)仅按照“在目录中创建文件”的顺序创建。一个简单的例子:$ mkdir a; 触摸一个/文件1; 触摸a / file-2 $ mkdir b; 触摸b / file-2; 触摸B /文件1 $(光盘;焦油-c |的md5sum。)fb29e7af140aeea5a2647974f7cdec77 - $(CD B;。焦油-c |的md5sum)a3a39358158a87059b9f111ccffa1023 -
Dieter_be

14

如果您只关心文件而不是空目录,则可以很好地工作:

find /path -type f | sort -u | xargs cat | md5sum


9

最适合我的解决方案:

find "$path" -type f -print0 | sort -z | xargs -r0 md5sum | md5sum

它对我最有效的原因:

  1. 处理包含空格的文件名
  2. 忽略文件系统元数据
  3. 检测文件是否已重命名

其他答案的问题:

文件系统元数据不会因以下原因而被忽略:

tar c - "$path" | md5sum

不处理包含空格的文件名,也不检测文件是否已重命名:

find /path -type f | sort -u | xargs cat | md5sum

4

如果您想要一个md5sum跨越整个目录,我会做类似的事情

cat *.py | md5sum 

1
对于子目录,请使用cat **.py| md5sum
拉蒙

3

校验所有文件,包括内容和文件名

grep -ar -e . /your/dir | md5sum | cut -c-32

与上述相同,但仅包括* .py文件

grep -ar -e . --include="*.py" /your/dir | md5sum | cut -c-32

您也可以按照符号链接进行操作

grep -aR -e . /your/dir | md5sum | cut -c-32

您可以考虑与grep一起使用的其他选项

-s, --no-messages         suppress error messages
-D, --devices=ACTION      how to handle devices, FIFOs and sockets;
-Z, --null                print 0 byte after FILE name
-U, --binary              do not strip CR characters at EOL (MSDOS/Windows)


2

从技术上讲,您只需要运行ls -lR *.py | md5sum。除非您担心有人会修改文件并将它们恢复到原始日期,并且从不更改文件大小,ls否则输出将应告诉您文件是否已更改。我的unix-foo很弱,因此您可能需要更多命令行参数来获取创建时间和修改时间以进行打印。ls还会告诉您文件的权限是否已更改(如果您不关心,我敢肯定有一些开关可以将其关闭)。


3
这可能适合某些用例,但通常您希望校验和仅反映内容而不反映日期。例如,如果我touch要更改日期(但更改其内容)的文件,则希望校验和保持不变。
托德·欧文


1

我遇到了同样的问题,所以我想出了一个脚本,该脚本仅列出目录中文件的md5sum,如果找到子目录,它将再次从该目录运行,为此,脚本必须能够在当前目录中运行目录或子目录(如果在$ 1中传递了所述参数)

#!/bin/bash

if [ -z "$1" ] ; then

# loop in current dir
ls | while read line; do
  ecriv=`pwd`"/"$line
if [ -f $ecriv ] ; then
    md5sum "$ecriv"
elif [ -d $ecriv ] ; then
    sh myScript "$line" # call this script again
fi

done


else # if a directory is specified in argument $1

ls "$1" | while read line; do
  ecriv=`pwd`"/$1/"$line

if [ -f $ecriv ] ; then
    md5sum "$ecriv"

elif [ -d $ecriv ] ; then
    sh myScript "$line"
fi

done


fi

我很确定,如果文件名包含空格或引号,则此脚本将失败。我发现bash脚本令人讨厌,但是我要做的是更改IFS。
本地主机

1

如果您想真正独立于文件系统属性以及某些tar版本的位级差异,则可以使用cpio:

cpio -i -e theDirname | md5sum

0

还有两个解决方案:

创造:

du -csxb /path | md5sum > file

ls -alR -I dev -I run -I sys -I tmp -I proc /path | md5sum > /tmp/file

检查:

du -csxb /path | md5sum -c file

ls -alR -I dev -I run -I sys -I tmp -I proc /path | md5sum -c /tmp/file

0

md5sum对我来说工作正常,但是我在sort文件名排序方面遇到问题。所以我改为按md5sum结果排序。我还需要排除一些文件才能创建可比较的结果。

find . -type f -print0 \ | xargs -r0 md5sum \ | grep -v ".env" \ | grep -v "vendor/autoload.php" \ | grep -v "vendor/composer/" \ | sort -d \ | md5sum

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.