【问题标题】:How can I efficiently compute the SHA1 sums of a bunch of chunks of a file from the command line?如何从命令行有效地计算一堆文件块的 SHA1 总和?
【发布时间】:2015-01-16 12:20:41
【问题描述】:

我有一个文件 f,我想在该文件上计算一个 SHA1 哈希序列,文件的每个 2 kB 块一个。例如,如果 f 的大小为 1G,我想计算大约 50 万个哈希:字节 0-2047、字节 2048-4095、字节 4096-6143、字节 6144-8192 各一个。理想情况下,我想通过一次读取文件并将结果流式传输到另一个文件或管道来完成所有这些操作。我知道splitsha1sum 命令,但我不确定如何将它们与其他命令结合以实现此目标。有没有像split 这样的东西可以避免创建中间文件并对计算这些 SHA1 和有用?

如果我在较低级别实现此功能,我当然会按顺序将文件读​​入一个小缓冲区,然后在为每个新块重用缓冲区之前计算 SHA1 总和,但我更喜欢简单的 bash如果有的话,就一个班轮。在 bash 中有没有好的方法来做到这一点(假设 f 可以包含空字节)?

【问题讨论】:

  • 文件可以包含空字节吗? (我猜答案是“是”,但我很可能会问它是“否”。由于in this unix.stackexchange.com question 指出的原因,如果文件可以包含空字节,您的选择会受到更多限制。)
  • 我知道could be done easily using Python。因此,如果您可以接受嵌入在 Bash 脚本中的小 Python……
  • 是的,在问题末尾添加了说明。
  • @5gon12eder,一个简单的 python 解决方案会很有趣,但我想它会比以sha1sum 为瓶颈的解决方案慢得多。
  • 我不认为 Python 解决方案会慢很多。无论如何,计算量大的部分都将在 C 代码中完成。

标签: bash sha1


【解决方案1】:

这是使用Python's hashlib 的解决方案。它足够小,可以合理地内联到 shell 脚本中。

#!/bin/bash -eu

python <<EOF
import hashlib

chunksize = 2048
md = hashlib.sha1()
with open("$1", 'rb') as istr:
    while True:
        chunk = istr.read(chunksize)
        if not chunk:
            break
        md.update(chunk)
        print(md.hexdigest())
EOF

我已使用存储在 ramdisk 中的 1 GiB 文件对其进行计时。 sha1sum 命令行工具花了 3.24 秒来散列整个文件。上面的脚本(标准输出通过管道传输到/dev/null)耗时 7.35 秒,大约是原来的两倍。这对我来说看起来很不错,尤其是考虑到它实际上做了更多的工作。

请注意,这会计算累积哈希(每个摘要涵盖所有先前的字节)。阅读其他答案后,我不确定这是否是您想要的。如果您想要独立的摘要,则必须将 md = hashlib.sha1() 移动到循环内。在这种情况下,上述基准测试需要 8.26 秒。

【讨论】:

  • + 1 用于一般方法和时序比较,虽然具体代码不太正确,因为它发出 cumulative 摘要(一个用于前 2KB ,一个用于前 4KB 等),这不是 OP 想要的。 (另外,md 不是 MD5 的吗?)
  • 我以为 OP 想要这个,但我已经在我的答案中添加了评论。改变不是什么大事。至少在我的俚语中,“md”代表“消息摘要”,它只是“哈希”的通用词。
  • 回复:“改改不是什么大事”:是的,但可能会影响时机?没有把握。回复:“'md' 代表'消息摘要'”:哦,duh,O.K.
【解决方案2】:

所以,这种方法适用于我手边的机器:

(
  file=large-file.txt
  size=$(stat -c %s "$file")
  for (( i = 0 ; i * 2048 < size ; ++i )) ; do
    head -c 2k | sha1sum -
  done < "$file"
)

或作为单行:

( file=large-file.txt ; size=$(stat -c %s "$file") ; for (( i = 0 ; i * 2048 < size ; ++i )) ; do ; head -c 2k | sha1sum - ; done < "$file" )

在我的机器上,for 循环的每次迭代只读取前 2KB 并将它们传递给 sha1sum,将文件的其余部分留给下一次迭代。

但是,我在head 的文档中看不到任何承诺这种行为的内容。 (head -c 2k 被记录为仅打印 2 KB,但这并不一定意味着它只会从标准输入中消耗 2 KB。)因此,尽管它至少可以在一个盒子上工作,但我不能保证它可以移植到您可能想在所有盒子上使用它。 (就此而言,-c 标志本身不是由 POSIX 指定的;相反,它是 GNU 实现的一个特性。)

【讨论】:

  • 如果你想要一些 posix 标准的东西,并且保证能准确读取 2kb 的大小,请使用 dd count=1 bs=2k。 (Posix 指定 k 是 1024。)
猜你喜欢
  • 1970-01-01
  • 2019-12-11
  • 2010-11-23
  • 1970-01-01
  • 2013-11-10
  • 1970-01-01
  • 2016-12-31
  • 2015-01-05
相关资源
最近更新 更多