Linux:计算给定文件夹和内容的单个哈希值?

Ben*_*n L 75 linux bash hash

当然必须有办法轻松做到这一点!

我已经尝试了Linux等命令行应用程序sha1sum,md5sum但它们似乎只能计算单个文件的哈希值并输出一个哈希值列表,每个文件一个.

我需要为文件夹的整个内容(而不仅仅是文件名)生成单个哈希.

我想做点什么

sha1sum /folder/of/stuff > singlehashvalue
Run Code Online (Sandbox Code Playgroud)

编辑:澄清一下,我的文件位于目录树的多个级别,它们并非都位于同一个根文件夹中.

Vat*_*ine 99

一种可能的方法是:

sha1sum path/to/folder/* | sha1sum

如果有一个完整的目录树,那么最好使用find和xargs.一个可能的命令是

find path/to/folder -type f -print0 | sort -z | xargs -0 sha1sum | sha1sum

最后,如果您还需要考虑权限和空目录:

(find path/to/folder -type f -print0  | sort -z | xargs -0 sha1sum;
 find path/to/folder \( -type f -o -type d \) -print0 | sort -z | \
   xargs -0 stat -c '%n %a') \
| sha1sum
Run Code Online (Sandbox Code Playgroud)

参数stat将导致它打印文件的名称,后跟其八进制权限.这两个发现将一个接一个地运行,导致磁盘IO的数量增加一倍,第一个查找所有文件名并校验内容,第二个查找所有文件和目录名,打印名称和模式.然后将"文件名和校验和"列表,后跟"具有权限的名称和目录"进行校验和,以获得较小的校验和.

  • @RichardBronosky - 我们假设我们有两个文件,A和B. A包含"foo",B包含"bar is here".使用您的方法,我们无法将它与两个文件C和D分开,其中C包含"foobar",D包含"在这里".通过单独散列每个文件然后散列所有"文件名哈希"对,我们可以看到差异. (4认同)
  • 并且不要忘记设置LC_ALL = POSIX,因此各种工具都会创建与语言环境无关的输出。 (2认同)
  • 我找到了猫| sha1sum比sha1sum快得多 SHA1SUM.YMMV,在你的系统上尝试以下每一个:time find path/to/folder -type f -print0 | sort -z | xargs -0 sha1sum | SHA1SUM; time find path/to/folder -type f -print0 | sort -z | xargs -0 cat | SHA1SUM (2认同)
  • 无论目录路径如何(即,当您想比较两个不同文件夹的哈希值时),为了使这项工作都能正常工作,您需要使用相对路径并更改为适当的目录,因为这些路径包含在最终哈希值中:`find ./folder -type f -print0 | 排序 -z | xargs -0 sha1sum | sha1sum` (2认同)
  • @robbles这是正确的,为什么我没有在`path/to/folder`位上放置一个初始的`/`. (2认同)

Dav*_*itt 22

  • 将目录提交到git,使用commit hash.请参阅metastore以获取控制权限的方法.

  • 使用文件系统入侵检测工具,如助手.

  • 哈希目录的tar球:

    tar cvf - /path/to/folder | sha1sum

  • 自己编写代码,比如vatine的oneliner:

    find /path/to/folder -type f -print0 | sort -z | xargs -0 sha1sum | sha1sum

  • 请注意,比较它们时,tar解决方案假定文件的顺序相同.它们是否取决于进行比较时文件所在的文件系统. (5认同)
  • git哈希不适用于此目的,因为文件内容只是其输入的一部分.即使对于分支的初始提交,哈希也会受到提交消息和提交元数据的影响,就像提交的时间一样.如果多次提交相同的目录结构,则每次都会得到不同的哈希,因此结果哈希不适合通过仅发送哈希来确定两个目录是否是彼此的精确副本. (5认同)
  • 焦油溶液+1.这是最快的,但是降低v.冗长只会减慢它的速度. (3认同)
  • @nos:使用最新版本的 GNU tar,可以使用 --sort=name 强制执行排序顺序。 (3认同)
  • @Zoltan,如果你使用树哈希而不是提交哈希,那么 git 哈希就完全没问题。 (2认同)

Wan*_*ang 21

到目前为止,最快的方法仍然是使用 tar。通过几个附加参数,我们还可以消除元数据造成的差异。

要使用 GNU tar 对目录进行哈希处理,需要确保在 tar 期间对路径进行排序,否则它总是不同的。

tar -C <root-dir> -cf - --sort=name <dir> | sha256sum
Run Code Online (Sandbox Code Playgroud)

忽略时间

如果您不关心访问时间或修改时间,也可以使用类似的方法--mtime='UTC 2019-01-01' 来确保所有时间戳都是相同的。

忽略所有权

通常我们需要添加--group=0 --owner=0 --numeric-owner统一所有者元数据。

忽略一些文件

使用--exclude=PATTERN

忽略权限

强烈建议您始终比较权限。

如果您确实不想比较权限,请使用:

--mode=777
Run Code Online (Sandbox Code Playgroud)

这会将所有文件权限授予 777。

例子:

$ echo a > test1/a.txt
$ echo b > test1/b.txt
$ tar -C ./ -cf - --sort=name test1 | sha256sum
e159ca984835cf4e1c9c7e939b7069d39b2fd2aa90460877f68f624458b1c95c  -
$ tar -C ./ -cf - --sort=name --mode=777 test1 | sha256sum
ef84fe411fb49bcf7967715b7854075004f1c7a7e4a57d2f3742afa4a54c40de  -
$ chmod 444 test1/a.txt
$ tar -C ./ -cf - --sort=name --mode=777 test1 | sha256sum
ef84fe411fb49bcf7967715b7854075004f1c7a7e4a57d2f3742afa4a54c40de  -
$ tar -C ./ -cf - --sort=name test1 | sha256sum
9b91430d954abb8a361b01de30f0995fb94a511c8fe1f7177ddcd475c85c65ff  -
Run Code Online (Sandbox Code Playgroud)

众所周知,有些 tar 没有--sort,请确保您有 GNU tar。

  • 这是涉及 GNU tar 的最佳答案,因为它确保文件内容和目录结构的比较一致。 (2认同)

S.L*_*ott 11

你可以做 tar -c /path/to/folder | sha1sum

  • 如果你想在另一台机器上复制那个校验和,tar可能不是一个好的选择,因为格式似乎有歧义的空间并且存在于许多版本中,因此另一台机器上的tar可能会产生来自相同文件的不同输出. (14认同)
  • 慢狗的有效顾虑是,如果您关心文件的内容,权限等,而不关心修改时间,则可以添加--mtime选项,如下所示:tar -c / path / to / folder --mtime =“ 1970 -01-01“ | sha1sum`。 (2认同)

ndb*_*ent 8

如果这是一个 git 存储库并且您想忽略 中的任何文件.gitignore,您可能需要使用以下命令:

git ls-files <your_directory> | xargs sha256sum | cut -d" " -f1 | sha256sum | cut -d" " -f1
Run Code Online (Sandbox Code Playgroud)

这对我来说效果很好。


Shu*_*app 6

如果您只是想检查文件夹中的某些内容是否发生了变化,我建议您这样做:

ls -alR --full-time /folder/of/stuff | sha1sum
Run Code Online (Sandbox Code Playgroud)

它只会给你一个ls输出的哈希值,它包含文件夹,子文件夹,它们的文件,它们的时间戳,大小和权限.几乎所有你需要确定的东西是否有变化.

请注意,此命令不会为每个文件生成哈希值,但这就是为什么它应该比使用find更快.

  • @Navin从这个问题尚不清楚是否需要散列文件内容或检测树中的更改。每种情况都有其用途。例如,在内核树中存储45K文件名不如单个哈希值实用。ls -lAgGR --block-size = 1 --time-style = +%s | sha1sum对我有用 (3认同)
  • 鉴于解决方案的简单性,我不确定为什么这没有更多的赞成票。谁能解释为什么这行不通? (2认同)

six*_*x-k 6

一种稳健而干净的方法

  • 首先,不要占用可用内存!以块为单位散列文件而不是提供整个文件。
  • 针对不同需求/目的的不同方法(以下所有或选择适用的方法):
    • 仅散列目录树中所有条目的条目名称
    • 散列所有条目的文件内容(留下元数据,inode 编号,ctime,atime,mtime,size 等,你懂的)
    • 对于符号链接,其内容是所指名称。散列它或选择跳过
    • 在散列条目的内容时遵循或不遵循(解析名称)符号链接
    • 如果是目录,则其内容只是目录条目。在递归遍历时,它们最终会被散列,但是该级别的目录条目名称是否应该被散列以标记该目录?在需要散列以快速识别更改而无需深入遍历以散列内容的用例中很有帮助。一个例子是文件的名称更改,但其余内容保持不变,它们都是相当大的文件
    • 处理好大文件(再次注意 RAM)
    • 处理非常深的目录树(注意打开的文件描述符)
    • 处理非标准文件名
    • 如何处理套接字、管道/FIFO、块设备、字符设备等文件?也必须散列它们吗?
    • 遍历时不要更新任何条目的访问时间,因为这对于某些用例会产生副作用和适得其反(直观?)。

这就是我的想法,任何花一些时间在这方面工作的人实际上都会遇到其他问题和角落案例。

这里有一个工具,非常节省内存,可以解决大多数情况,可能有点粗糙,但非常有帮助。

的示例用法和输出dtreetrawl

Usage:
  dtreetrawl [OPTION...] "/trawl/me" [path2,...]

Help Options:
  -h, --help                Show help options

Application Options:
  -t, --terse               Produce a terse output; parsable.
  -j, --json                Output as JSON
  -d, --delim=:             Character or string delimiter/separator for terse output(default ':')
  -l, --max-level=N         Do not traverse tree beyond N level(s)
  --hash                    Enable hashing(default is MD5).
  -c, --checksum=md5        Valid hashing algorithms: md5, sha1, sha256, sha512.
  -R, --only-root-hash      Output only the root hash. Blank line if --hash is not set
  -N, --no-name-hash        Exclude path name while calculating the root checksum
  -F, --no-content-hash     Do not hash the contents of the file
  -s, --hash-symlink        Include symbolic links' referent name while calculating the root checksum
  -e, --hash-dirent         Include hash of directory entries while calculating root checksum
Run Code Online (Sandbox Code Playgroud)

人类友好输出的片段:

...
... //clipped
...
/home/lab/linux-4.14-rc8/CREDITS
        Base name                    : CREDITS
        Level                        : 1
        Type                         : regular file
        Referent name                :
        File size                    : 98443 bytes
        I-node number                : 290850
        No. directory entries        : 0
        Permission (octal)           : 0644
        Link count                   : 1
        Ownership                    : UID=0, GID=0
        Preferred I/O block size     : 4096 bytes
        Blocks allocated             : 200
        Last status change           : Tue, 21 Nov 17 21:28:18 +0530
        Last file access             : Thu, 28 Dec 17 00:53:27 +0530
        Last file modification       : Tue, 21 Nov 17 21:28:18 +0530
        Hash                         : 9f0312d130016d103aa5fc9d16a2437e

Stats for /home/lab/linux-4.14-rc8:
        Elapsed time     : 1.305767 s
        Start time       : Sun, 07 Jan 18 03:42:39 +0530
        Root hash        : 434e93111ad6f9335bb4954bc8f4eca4
        Hash type        : md5
        Depth            : 8
        Total,
                size           : 66850916 bytes
                entries        : 12484
                directories    : 763
                regular files  : 11715
                symlinks       : 6
                block devices  : 0
                char devices   : 0
                sockets        : 0
                FIFOs/pipes    : 0
Run Code Online (Sandbox Code Playgroud)