141

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

最好的方法是什么?


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

4

16 回答 16

169

即时创建一个 tar 存档文件并将其通过管道传输到md5sum

tar c dir | md5sum

这会产生一个单一的 MD5 哈希值,该值对于您的文件和子目录设置应该是唯一的。没有在磁盘上创建文件。

于 2009-11-01T15:47:01.593 回答
160
find /path/to/dir/ -type f -name "*.py" -exec md5sum {} + | awk '{print $1}' | sort | md5sum

find命令列出所有以 .py 结尾的文件。为每个 .py 文件计算 MD5 哈希值。AWK 用于挑选 MD5 哈希值(忽略文件名,文件名可能不是唯一的)。对 MD5 哈希值进行排序。然后返回这个排序列表的 MD5 哈希值。

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

rsync -a ~/pybin/ ~/pybin2/

我重命名了~/pybin2中的一些文件。

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

2bcf49a4d19ef9abd284311108d626f1  -
于 2009-11-01T22:15:39.627 回答
53

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是为了确保跨系统的可靠排序顺序
  • 这并没有区分目录“named\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

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

于 2011-10-20T15:27:52.487 回答
17

如果您只关心文件而不关心空目录,这很好用:

find /path -type f | sort -u | xargs cat | md5sum
于 2013-04-09T21:33:31.880 回答
10

为了完整起见,有md5deep(1);由于 *.py 过滤器要求,它不能直接适用,但应该与 find(1) 一起使用。

于 2013-02-04T21:58:16.413 回答
10

最适合我的解决方案:

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
于 2015-04-08T10:28:55.073 回答
4

如果你想要一个跨越整个目录的 MD5 哈希值,我会做类似的事情

cat *.py | md5sum
于 2009-11-01T14:39:16.910 回答
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)
于 2015-03-02T14:10:02.250 回答
2

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

于 2009-11-01T22:43:13.717 回答
2

GNU find

find /path -type f -name "*.py" -exec md5sum "{}" +;
于 2009-11-01T14:50:58.710 回答
2

Using md5deep:

md5deep -r FOLDER | awk '{print $1}' | sort | md5sum

于 2014-07-17T21:07:38.247 回答
1

我遇到了同样的问题,所以我想出了这个脚本,它只列出目录中文件的 MD5 哈希值,如果它找到一个子目录,它会从那里再次运行,为此脚本必须能够运行通过当前目录或子目录,如果所述参数传入 $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
于 2013-03-16T21:39:43.180 回答
1

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

cpio -i -e theDirname | md5sum
于 2013-11-25T13:49:11.330 回答
1

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

于 2018-11-09T22:33:44.627 回答
1

我想补充一点,如果您尝试对 Git 存储库中的文件/目录执行此操作以跟踪它们是否已更改,那么这是最好的方法:

git log -1 --format=format:%H --full-diff <file_or_dir_name>

如果它不是 Git 目录/存储库,那么ire_and_curses 的答案可能是最好的选择:

tar c <dir_name> | md5sum

但是,请注意,tar如果您在不同的操作系统和其他东西中运行该命令,它将更改输出哈希。如果您想对此免疫,这是最好的方法,即使乍一看它看起来不是很优雅:

find <dir_name> -type f -print0 | sort -z | xargs -0 md5sum | md5sum | awk '{ print $1 }'
于 2020-11-03T21:35:30.627 回答
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
于 2016-01-29T14:34:48.453 回答