同时计算多个摘要(md5,sha256)?

Lek*_*eyn 27 shell-script hashsum parallelism

假设磁盘 I/O 和可用 RAM 是瓶颈(而 CPU 时间不是限制),是否存在可以一次计算多个消息摘要的工具?

我对计算大文件(以千兆字节为单位)的 MD-5 和 SHA-256 摘要特别感兴趣,最好是并行计算。我试过openssl dgst -sha256 -md5,但它只使用一种算法计算散列。

预期行为的伪代码:

for each block:
    for each algorithm:
        hash_state[algorithm].update(block)
for each algorithm:
    print algorithm, hash_state[algorithm].final_hash()
Run Code Online (Sandbox Code Playgroud)

Mat*_*off 29

退房pee(”tee standard input to pipes来自“) moreutils。这基本上等同于 Marco 的tee命令,但键入要简单一些。

$ echo foo | pee md5sum sha256sum
d3b07384d113edec49eaa6238ad5ff00  -
b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c  -
Run Code Online (Sandbox Code Playgroud)
$ pee md5sum sha256sum <foo.iso
f109ffd6612e36e0fc1597eda65e9cf0  -
469a38cb785f8d47a0f85f968feff0be1d6f9398e353496ff7aa9055725bc63e  -
Run Code Online (Sandbox Code Playgroud)


Mar*_*rco 10

您可以使用for循环来遍历单个文件,然后tee 结合使用进程替换(在 Bash 和 Zsh 等中工作)以管道传输到不同的校验和。

例子:

for file in *.mkv; do
  tee < "$file" >(sha256sum) | md5sum
done
Run Code Online (Sandbox Code Playgroud)

您还可以使用两个以上的校验和:

for file in *.mkv; do
  tee < "$file" >(sha256sum) >(sha384sum) | md5sum
done
Run Code Online (Sandbox Code Playgroud)

这样做的缺点是校验和不知道文件名,因为它是作为标准输入传递的。如果这是不可接受的,您必须手动发出文件名。完整示例:

for file in *.mkv; do
  echo "$file"
  tee < "$file" >(sha256sum) >(sha384sum) | md5sum
  echo
done > hashfilelist
Run Code Online (Sandbox Code Playgroud)

  • 为了使输出与 `*sum` 系列工具兼容,可以使用以下 sed 表达式: `sed "s;-\$;${file//;/\\;};` (替换了结尾的 ` -` 文件名,但确保文件名正确转义)。 (2认同)

PM *_*ing 6

遗憾的是,openssl 实用程序不接受多个摘要命令;我想对多个文件执行相同的命令是一种更常见的使用模式。FWIW,我的系统(Mepis 11)上的 openssl 实用程序版本只有 sha 和 sha1 的命令,没有任何其他 sha 变体。但我确实有一个名为 sha256sum 的程序,以及 md5sum。

这是一个简单的 Python 程序,dual_hash.py,可以满足您的需求。64k 的块大小似乎最适合我的机器(Intel Pentium 4 2.00GHz 和 2G RAM),YMMV。对于小文件,其速度与连续运行 md5sum 和 sha256sum 大致相同。但是对于较大的文件,它要快得多。例如,在一个 1967063040 字节的文件(一个装满 mp3 文件的 SD 卡的磁盘映像)上,md5sum + sha256sum 需要大约 1m44.9s,dual_hash.py 需要 1m0.312s。

双哈希.py

#! /usr/bin/env python

''' Calculate MD5 and SHA-256 digests of a file simultaneously

    Written by PM 2Ring 2014.10.23
'''

import sys
import hashlib

def digests(fname, blocksize):
    md5 = hashlib.md5()
    sha = hashlib.sha256()
    with open(fname, 'rb') as f:
        while True:
            block = f.read(blocksize)
            if not block:
                break
            md5.update(block)
            sha.update(block)

    print("md5: %s" % md5.hexdigest())
    print("sha256: %s" % sha.hexdigest())

def main(*argv):
    blocksize = 1<<16 # 64kB
    if len(argv) < 2:
        print("No filename given!\n")
        print("Calculate md5 and sha-256 message digests of a file.")
        print("Usage:\npython %s filename [blocksize]\n" % sys.argv[0])
        print("Default blocksize=%d" % blocksize)
        return 1

    fname = argv[1]

    if len(argv) > 2:
        blocksize = int(sys.argv[2])

    print("Calculating MD5 and SHA-256 digests of %r using a blocksize of %d" % (fname, blocksize))
    digests(fname, blocksize)

if __name__ == '__main__':
    sys.exit(main(*sys.argv))
Run Code Online (Sandbox Code Playgroud)

我想这个程序的 C/C++ 版本会快一点,但不会快很多,因为大部分工作是由 hashlib 模块完成的,它用 C(或 C++)编写的。正如你上面提到的,大文件的瓶颈是 IO 速度。


ter*_*don 5

你总是可以使用类似GNU parallel 的东西:

echo "/path/to/file" | parallel 'md5sum {} & sha256sum {}'
Run Code Online (Sandbox Code Playgroud)

或者,只需在后台运行两者之一:

md5sum /path/to/file & sha256sum /path/to/file
Run Code Online (Sandbox Code Playgroud)

或者,将输出保存到不同的文件并在后台运行多个作业:

for file in *; do
    md5sum "$file" > "$file".md5 &
    sha256sum "$file" > "$file".sha &
done
Run Code Online (Sandbox Code Playgroud)

这将启动md5sumsha256sum您拥有的文件一样多的实例,并且它们都将并行运行,将它们的输出保存到相应的文件名中。不过要小心,如果你有很多文件,这会变得很重。

  • @Twinkles 引用上面的 Lekensteyn 的话,“这种方法的问题在于一个命令可能比另一个命令更快,从而导致磁盘缓存被清空并稍后用相同的数据重新填充。” (2认同)
  • @MattNordhoff 智能 I/O 调度程序应该注意和优化的另一件事。有人可能会想:“I/O 调度程序考虑到这种情况有多难?” 但是由于 I/O 调度器应该考虑到足够多的不同场景,它突然变成了一个难题。所以我同意人们不应该假设缓存会解决这个问题。 (2认同)