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

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

最好的方法是什么?


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

162818 次浏览

如果您想要一个跨越整个目录的 MD5散列值,我可以这样做

cat *.py | md5sum

GNU 发现

find /path -type f -name "*.py" -exec md5sum "{}" +;

动态创建一个 tar 归档文件,并将其导入 md5sum:

tar c dir | md5sum

这将产生一个 MD5散列值,该值对于文件和子目录设置应该是唯一的。磁盘上不创建任何文件。

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

翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳翻译: 奇芳命令列出以. py 结尾的所有文件。 计算每个。Py 文件。AWK 用于剔除 MD5散列值(忽略可能不是唯一的文件名)。 对 MD5哈希值进行排序。然后返回此排序列表的 MD5哈希值。

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

rsync -a ~/pybin/ ~/pybin2/

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

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

2bcf49a4d19ef9abd284311108d626f1  -

为了考虑文件布局(路径) ,如果文件被重命名或移动,校验和就会发生变化,这个命令可以简化:

find /path/to/dir/ -type f -name "*.py" -exec md5sum {} + | md5sum

对于带有 md5的 macOS:

find /path/to/dir/ -type f -name "*.py" -exec md5 {} + | md5

从技术上讲,您只需要运行 ls -lR *.py | md5sum。除非您担心有人修改这些文件,并将它们修改回原来的日期,而且永远不会更改文件的大小,否则 ls的输出应该会告诉您文件是否已经更改。我的 unix-foo 比较弱,所以您可能需要更多的命令行参数来获得创建时间和打印修改时间。ls还会告诉您文件的权限是否发生了变化(如果您不关心这一点,我确信有开关可以关闭该权限)。

Ire _ and _ curses 关于使用 tar c <dir>的建议存在一些问题:

  • Tar 按照存储在文件系统中的顺序处理目录条目,并且无法更改这个顺序。如果您在不同的位置有相同的目录,而且我不知道有什么方法可以解决这个问题(tar 不能按照特定的顺序对其输入文件进行“排序”) ,那么这将有效地产生完全不同的结果。
  • 我通常关心 groupid 和 owner 数字是否相同,而不一定关心 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”的目录和“命名为”和“命名为 withanewline”的两个目录,但发生这种情况的可能性似乎很小。人们通常使用 find-print0标志来修复这个问题,但是由于这里还有其他的东西,我只能看到一些解决方案,这些解决方案会使命令变得更加复杂。

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

幸运的是,我没有名称中带有换行符的文件/目录,所以在那个系统上这不是一个问题。

为了完整起见,有 Md5deep (1); 由于 * 的原因,它不能直接应用。Py 过滤器的要求,但是应该与 find (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

如果您只关心文件而不是空目录,那么这种方法非常有效:

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

如果您想真正独立于文件系统属性和某些 一个 href = “ https://en.wikipedia.org/wiki/Tar _% 28computer% 29”rel = “ nofollow noReferrer”> tar 版本的位级差异,可以使用 Cpio:

cpio -i -e theDirname | md5sum

使用 md5deep:

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

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

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)

一个对我最有效的解决方案:

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

还有两种解决方案:

创造:

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

md5sum对我来说很好用,但是我在 sort和排序文件名方面有问题。所以我改用 md5sum结果排序。我还需要排除一些文件,以便创建可比较的结果。

查找-类型 f-print0 | xargs-r0 md5sum | grep-v“ . env” | grep-v“卖主/autoload.php” | grep-v“供应商/作曲家/” | sort-d | md5sum

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

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

如果它不是 Git 目录/存储库,那么 用愤怒和咒骂来回答可能是最好的选择:

tar c <dir_name> | md5sum

但是,请注意,如果您在不同的操作系统中运行它,tar命令将更改输出散列。如果你想对此免疫,这是最好的方法,尽管乍一看它并不优雅:

find <dir_name> -type f -print0 | sort -z | xargs -0 md5sum | md5sum | awk '{ print $1 }'