macos 中目录的 shasum

macos 中目录的 shasum

我正在编写一个 shell 脚本,使用它shasum来检查目录的内容是否已更改。

在 Linux 和 FreeBSD 上,shasum当我这样做时,它们有相同的行为shasum <directory>,但是在 MacOS 上,它们shasum给我哈希值仅适用于文件

FreeBSD

$ shasum CONTENTS/
7f986e5e5289c59db1bba48df92ffe4707830aaa  CONTENTS/

Linux

$ shasum CONTENTS/
7f986e5e5289c59db1bba48df92ffe4707830aaa  CONTENTS/

苹果系统

$ shasum CONTENTS/
shasum: CONTENTS/: 

我怎样才能计算 MacOS 中目录的哈希值?

尝试 1:使用 TAR 和管道

尝试使用但似乎这个 tar 选项在 MacOS 上不起作用。

tar cO CONTENTS/ | shasum
tar: Option -O is not permitted in mode -c
da39a3ee5e6b4b0d3255bfef95601890afd80709  -

尝试 2:使用 FIND/EXEC

MacOS 和 FreeBSD 之间是一致的,但 Linux 返回了一个奇怪的哈希值

find CONTENTS -type f -exec shasum {} \; | sort -k 2 | shasum

Linux

c2ddb9bc5f543e956f5cdcc76750cb78cc5f26f3

FreeBSD

3ac2a9d4e2fc5d2d2ec3c7f612e680990cc35824

苹果系统

3ac2a9d4e2fc5d2d2ec3c7f612e680990cc35824

关于 TAR 的其他发现

tar非常棒,因为它可以“存档”一个文件夹,然后我就可以这样做了,但是文件夹结构的“遍历”shasum顺序是tar跨操作系统不一致。正如一些助手在评论中提到的,我应该tar在所有系统中使用相同版本。

仅举一个例子,在系统 1 上我有这个命令:

drwxr-xr-x  0 root   wheel       0 27 Jul 07:23 usr/
-rw-r--r--  0 root   wheel       0 27 Jul 07:25 usr/aaa
drwxr-xr-x  0 root   wheel       0 27 Jul 07:25 usr/f1/
-rw-r--r--  0 root   wheel       0 27 Jul 07:25 usr/f1/aaa
drwxr-xr-x  0 root   wheel       0 27 Jul 07:25 usr/f1/f0/
-rw-r--r--  0 root   wheel       0 27 Jul 07:25 usr/f1/f0/aaa
drwxr-xr-x  0 root   wheel       0 27 Jul 07:25 usr/f2/
-rw-r--r--  0 root   wheel       0 27 Jul 07:25 usr/f2/aaa
drwxr-xr-x  0 root   wheel       0 27 Jul 07:25 usr/f2/f1/
-rw-r--r--  0 root   wheel       0 27 Jul 07:25 usr/f2/f1/aaa
drwxr-xr-x  0 root   wheel       0 27 Jul 07:25 usr/f2/f1/f0/
-rw-r--r--  0 root   wheel       0 27 Jul 07:25 usr/f2/f1/f0/aaa
drwxr-xr-x  0 root   wheel       0 27 Jul 07:25 usr/f3/
-rw-r--r--  0 root   wheel       0 27 Jul 07:25 usr/f3/aaa
drwxr-xr-x  0 root   wheel       0 27 Jul 07:25 usr/f3/f2/
-rw-r--r--  0 root   wheel       0 27 Jul 07:25 usr/f3/f2/aaa
drwxr-xr-x  0 root   wheel       0 27 Jul 07:25 usr/f3/f2/f1/
-rw-r--r--  0 root   wheel       0 27 Jul 07:25 usr/f3/f2/f1/aaa

在系统 2 上我有以下顺序:

drwxr-xr-x  0 root   wheel       0 27 Jul 07:23 usr/
-rw-r--r--  0 root   wheel       0 27 Jul 07:25 usr/aaa
drwxr-xr-x  0 root   wheel       0 27 Jul 07:25 usr/f1/
drwxr-xr-x  0 root   wheel       0 27 Jul 07:25 usr/f2/
drwxr-xr-x  0 root   wheel       0 27 Jul 07:25 usr/f3/
-rw-r--r--  0 root   wheel       0 27 Jul 07:25 usr/f3/aaa
drwxr-xr-x  0 root   wheel       0 27 Jul 07:25 usr/f3/f2/
-rw-r--r--  0 root   wheel       0 27 Jul 07:25 usr/f3/f2/aaa
drwxr-xr-x  0 root   wheel       0 27 Jul 07:25 usr/f3/f2/f1/
-rw-r--r--  0 root   wheel       0 27 Jul 07:25 usr/f3/f2/f1/aaa
-rw-r--r--  0 root   wheel       0 27 Jul 07:25 usr/f2/aaa
drwxr-xr-x  0 root   wheel       0 27 Jul 07:25 usr/f2/f1/
-rw-r--r--  0 root   wheel       0 27 Jul 07:25 usr/f2/f1/aaa
drwxr-xr-x  0 root   wheel       0 27 Jul 07:25 usr/f2/f1/f0/
-rw-r--r--  0 root   wheel       0 27 Jul 07:25 usr/f2/f1/f0/aaa
-rw-r--r--  0 root   wheel       0 27 Jul 07:25 usr/f1/aaa
drwxr-xr-x  0 root   wheel       0 27 Jul 07:25 usr/f1/f0/
-rw-r--r--  0 root   wheel       0 27 Jul 07:25 usr/f1/f0/aaa

从某个tar角度来看,这一切都很好,但由于顺序,shasum产生了不同的哈希值。

结论

shasum在 Linux 和 BSD 中检查单个文件哈希值是一致的,但是,当涉及到目录时,一致性只发生在 MacOS 和 FreeBSD 上,这可能是由于文件的排序方式造成的。

如果使用命令强制排序find,则只能在 FreeBSD 和 MacOS 中获得一致性,但是这种方法耗时较长,因为需要花费大量时间来计算每个文件的哈希值,然后计算整个结构的哈希值。

使用tar创建临时文件然后执行的操作shasum也发现 Linux 和 BSD 之间不一致,也许是因为存档方法不同。

我认为唯一的出路就是重新设计我的解决方案

答案1

mtree就是您想要的工具。

认为:

$ mkdir foo
$ date > foo/date1; sleep 3
$ date > foo/date2; sleep 3
$ date > foo/date3
$ grep . foo/*
foo/date1:Wed Jul 24 16:11:32 PDT 2019
foo/date2:Wed Jul 24 16:11:35 PDT 2019
foo/date3:Wed Jul 24 16:11:38 PDT 2019
$ find . -ls
7318841   0 drwxr-xr-x    3 admin    staff     102 Jul 24 16:11 .
7318847   0 drwxr-xr-x    5 admin    staff     170 Jul 24 16:11 ./foo
7318849   8 -rw-r--r--    1 admin    staff      29 Jul 24 16:11 ./foo/date1
7318851   8 -rw-r--r--    1 admin    staff      29 Jul 24 16:11 ./foo/date2
7318853   8 -rw-r--r--    1 admin    staff      29 Jul 24 16:11 ./foo/date3

创建目录的参考清单foo并将其存储在foo.mtree

$ mtree -c -K sha256digest -p foo > foo.mtree

现在去处理该目录中的任何文件。

$ touch foo/date3

再次运行mtree并传递您之前创建的清单,它将mtree告诉您发生了哪些变化:

$ mtree -p foo < foo.mtree || echo fail
date3 changed
        modification time expected Wed Jul 24 16:11:38 2019 found Wed Jul 24 16:14:00 2019
fail

$ echo '$ date > foo/date2' >> bar
$ mtree -p foo < foo.mtree || echo fail
date2 changed
        modification time expected Wed Jul 24 16:11:35 2019 found Wed Jul 24 16:19:40 2019
        SHA-256 expected c76a568f08d98c2830f2fdfb42415c3ec15341b8741450d4bbd863f1d5c4c691 found ddcf8d07785bfe4d031a989339835dc3b8b44653019568dcee612c44fc8e2f70
date3 changed
        modification time expected Wed Jul 24 16:11:38 2019 found Wed Jul 24 16:14:00 2019
fail

foo自清单创建以来缺少或添加的任何文件也将被报告:

$ mv foo/date1 foo/date4
$ mtree -p foo < foo.mtree || echo fail
. changed
        modification time expected Wed Jul 24 16:11:38 2019 found Wed Jul 24 16:21:38 2019
date2 changed
        modification time expected Wed Jul 24 16:11:35 2019 found Wed Jul 24 16:19:40 2019
        SHA-256 expected c76a568f08d98c2830f2fdfb42415c3ec15341b8741450d4bbd863f1d5c4c691 found ddcf8d07785bfe4d031a989339835dc3b8b44653019568dcee612c44fc8e2f70
date3 changed
        modification time expected Wed Jul 24 16:11:38 2019 found Wed Jul 24 16:14:00 2019
date4 extra
./date1 missing
fail

答案2

林特将会做(我认为是)你想要做的事。

相关要点:

  • 它默认不使用 SHA,但可以告知它使用。
  • 它可以通过 homebrew 安装在 MacOS 上。
  • 默认情况下,它不会计算单个指定目录的校验和。可以指示它从给定的起点计算所有目录的校验和,以此作为查找该点以下“重复”目录的方法。但作为副作用,它也会执行您似乎要求的操作。
  • 对于您所寻找的东西来说,它可能有些过度,而且可能需要花费一些时间才能找出最佳的选项标志,但它相当强大。
  • 弄清楚要使用哪些标志可能很棘手。获取目录校验和很容易,但要不是做其他事情,可能会很棘手。(虽然要清楚,它实际上并没有修改任何东西。最多,它会生成一个 shell 脚本,您可以稍后手动运行该脚本,以根据需要修改内容。您似乎需要的是 JSON 和/或 CSV 输出文件,它们将为您提供您正在寻找的目录校验和。)

我在 Bash 脚本中使用 rmlint 来查找重复的目录。下面这个命令会尽量少做你想做的事情,尽可能少做其他事情:

rmlint "base/dir/to/start/from" --see-symlinks --hidden --algorithm=sha256 --types=none,duplicatedirs --no-backup -o csv:log.csv

相关内容