คำนวณการย่อยหลายรายการพร้อมกัน (md5, sha256) พร้อมกันไหม


24

ภายใต้สมมติฐานว่าดิสก์ 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()

คุณสามารถเริ่มต้นเพียงหนึ่งตัวอย่างในพื้นหลังแล้วทั้ง hashes ทำงานแบบขนาน:for i in file1 file2 …; do sha256 "$i"& md5sum "$i"; done
มาร์โก

2
@Marco ปัญหาเกี่ยวกับวิธีการนั้นคือคำสั่งหนึ่งอาจเร็วกว่าอีกคำสั่งหนึ่งส่งผลให้ดิสก์แคชที่ได้รับการล้างและเติมใหม่ในภายหลังด้วยข้อมูลเดียวกัน
Lekensteyn

1
หากคุณกำลังกังวลเกี่ยวกับแคชดิสก์คุณสามารถอ่านในไฟล์เพียงครั้งเดียว: for i in file1 file2 …; do tee < "$i" >(sha256sum) | md5sum ; doneแล้วคุณจะต้องเพิ่มรหัสเพิ่มเติมเพื่อทำเครื่องหมายชื่อไฟล์เพราะมันจะถูกส่งเป็น input มาตรฐานและmd5sum sha256sum
Marco

คำตอบ:


28

ตรวจสอบpee(" tee standard input to pipes") moreutilsจาก นี่เป็นteeคำสั่งที่เทียบเท่ากับคำสั่งของมาร์โกแต่พิมพ์ได้ง่ายกว่าเล็กน้อย

$ echo foo | pee md5sum sha256sum
d3b07384d113edec49eaa6238ad5ff00  -
b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c  -
$ pee md5sum sha256sum <foo.iso
f109ffd6612e36e0fc1597eda65e9cf0  -
469a38cb785f8d47a0f85f968feff0be1d6f9398e353496ff7aa9055725bc63e  -

คำสั่งที่ดี! ฉันได้ติดตั้งแพคเกจที่มีประโยชน์มากนี้ไปแล้วไม่รู้ชื่อยูทิลิตี้ตลกนี้
Lekensteyn

1
peeมีอินเทอร์เฟซที่ดีที่สุดการเปรียบเทียบเวลากับเครื่องมืออื่น ๆ สามารถพบได้ในโพสต์นี้ซึ่งยังแสดงให้เห็นถึงเครื่องมือ Python แบบมัลติเธรด
Lekensteyn

น่าเสียดายที่moreutilsความขัดแย้งกับGNU parallelระบบ Debian ของฉัน…เป็นเรื่องดีที่รู้ว่ามีเครื่องมือดังกล่าว
liori

@Lekensteyn: ฉันได้รับข้อขัดแย้งในระดับแพ็คเกจ (เช่นaptitudeไม่ให้ฉันมีแพ็คเกจทั้งสองพร้อมกัน)
liori

@liori น่าเสียดายที่ Debian ใช้วิธีนี้เป็นอย่างดี บน Arch Linux มีmoreutils-parallelชื่อเพื่อหลีกเลี่ยงความขัดแย้ง
Lekensteyn

10

คุณสามารถใช้การforวนซ้ำเพื่อวนไฟล์แต่ละไฟล์จากนั้นใช้tee ร่วมกับการทดแทนกระบวนการ

ตัวอย่าง:

for file in *.mkv; do
  tee < "$file" >(sha256sum) | md5sum
done

คุณสามารถใช้เครื่องตรวจสอบมากกว่าสองเครื่อง:

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

สิ่งนี้มีข้อเสียที่ผู้ตรวจสอบไม่ทราบชื่อไฟล์เพราะจะถูกส่งเป็นอินพุตมาตรฐาน หากไม่เป็นที่ยอมรับคุณต้องปล่อยชื่อไฟล์ด้วยตนเอง ตัวอย่างที่สมบูรณ์:

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

1
เพื่อให้เอาต์พุตเข้ากันได้กับ*sumตระกูลของเครื่องมือนิพจน์ sed นี้สามารถใช้แทน: sed "s;-\$;${file//;/\\;};(แทนที่ส่วนท้าย-ด้วยชื่อไฟล์ แต่ให้แน่ใจว่าชื่อไฟล์ได้รับการหลบหนีอย่างถูกต้อง)
Lekensteyn

AFAICS zshมันจะทำงานเฉพาะใน ใน ksh93 และ bash เอาต์พุตของ sha256sum ไปที่ md5sum คุณจะต้องการ: { tee < "$file" >(sha256sum >&3) | md5sum; } 3>&1. ดูunix.stackexchange.com/q/153896/22565สำหรับปัญหาย้อนกลับ
Stéphane Chazelas

6

เป็นเรื่องน่าเสียดายที่ยูทิลิตี้ openssl ไม่ยอมรับคำสั่งย่อยหลายคำสั่ง ฉันเดาว่าการใช้คำสั่งเดียวกันกับไฟล์หลาย ๆ ไฟล์เป็นรูปแบบการใช้งานทั่วไปที่มากขึ้น FWIW เวอร์ชันของยูทิลิตี openssl บนระบบของฉัน (Mepis 11) มีคำสั่งสำหรับ sha และ sha1 เท่านั้นไม่ใช่ตัวแปร sha อื่น ๆ แต่ฉันมีโปรแกรมที่เรียกว่า sha256sum เช่นเดียวกับ md5sum

นี่คือโปรแกรม Python แบบง่าย ๆ dual_hash.py ซึ่งเป็นสิ่งที่คุณต้องการ ขนาดบล็อก 64k ดูเหมือนจะเหมาะสมที่สุดสำหรับเครื่องของฉัน (Intel Pentium 4 2.00GHz พร้อม RAM 2G), YMMV สำหรับไฟล์ขนาดเล็กความเร็วของไฟล์นั้นจะเหมือนกับการรัน md5sum และ sha256sum อย่างต่อเนื่อง แต่สำหรับไฟล์ขนาดใหญ่มันเร็วกว่ามาก เช่นในไฟล์ขนาด 1967063040 ไบต์ (ดิสก์อิมเมจของ SD การ์ดเต็มไปด้วยไฟล์ MP3) md5sum + sha256sum ใช้เวลาประมาณ 1m44.9s, dual_hash.py ใช้เวลา 1m0.312s

dual_hash.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))

ฉันคิดว่า C / C ++ รุ่นของโปรแกรมนี้จะเป็นเล็ก ๆ น้อย ๆ ได้เร็วขึ้น แต่ไม่มากเนื่องจากส่วนใหญ่ของการทำงานจะถูกดำเนินการโดยโมดูล hashlib ซึ่งถูกเขียนใน C (หรือ C ++) และตามที่คุณระบุไว้ข้างต้นคอขวดสำหรับไฟล์ขนาดใหญ่คือความเร็ว IO


สำหรับไฟล์ 2.3G รุ่นนี้มีความเร็วเทียบเคียงได้เมื่อเปรียบเทียบกับmd5sumและsha256sumรวมกัน (4.7s + 14.2s vs 18.7s สำหรับสคริปต์ Python นี้ไฟล์ในแคช 33.6 วินาทีสำหรับการทำงานแบบเย็น) 64KiB เทียบกับ 1MiB ไม่ได้เปลี่ยนสถานการณ์ เมื่อใส่ความคิดเห็นของรหัส 5.1s ใช้กับ md5 (n = 3), 14.6s สำหรับ sha1 (n = 3) ทดสอบกับ i5-460M พร้อม 8GB RAM ฉันเดาว่าสิ่งนี้จะได้รับการปรับปรุงให้ดียิ่งขึ้นโดยใช้เธรดที่มากขึ้น
Lekensteyn

C หรือ C ++ อาจไม่สำคัญว่ามีการใช้งานรันไทม์จำนวนมากในโมดูล OpenSSL อย่างไรก็ตาม (ใช้โดย hashlib) หัวข้ออื่น ๆ ไม่เพิ่มความเร็วให้ดูนี้โพสต์เกี่ยวกับสคริปต์แบบมัลติเธรดหลาม
Lekensteyn

@PM 2Ring - แค่ทราบ หลังจากคำสั่งพิมพ์ในฟังก์ชั่นย่อยของคุณ () คุณต้องล้างอย่างน้อย sha ฉันไม่สามารถพูดได้ว่าคุณควรล้าง md5 หรือไม่ ฉันจะใช้ "del sha" หากคุณไม่มีไฟล์ทุกไฟล์หลังจากไฟล์แรกจะมีแฮชที่ไม่ถูกต้อง เพื่อพิสูจน์ให้ทำ tmp dir และคัดลอกไฟล์ลงไป ตอนนี้ทำสำเนาของไฟล์นั้น 2 ไฟล์แล้วเรียกใช้สคริปต์ของคุณ คุณจะได้รับแฮช 3 แบบซึ่งไม่ใช่สิ่งที่คุณต้องการ แก้ไข: ฉันคิดว่าฟังก์ชั่นอ่านไฟล์หลายชุดไม่ใช่แค่อ่านไฟล์ทีละไฟล์ ... ไม่สนใจการใช้งานนี้ ;)
Terry Wendt

1
@TerryWendt คุณทำให้ฉันกังวลอยู่ที่นั่นสักครู่ :) ใช่digestsเพียงประมวลผลไฟล์เดียวในการโทรแต่ละครั้ง ดังนั้นแม้ว่าคุณจะเรียกมันว่าการวนซ้ำมันจะสร้าง md5 & sha บริบทใหม่ในการโทรแต่ละครั้ง FWIW คุณสามารถเพลิดเพลินกับแฮช SHA-256 ที่กลับมาทำงานได้อีกครั้ง
PM 2Ring

5

คุณสามารถใช้อะไรก็ได้เช่นGNU ขนาน :

echo "/path/to/file" | parallel 'md5sum {} & sha256sum {}'

หรือเพียงเรียกใช้หนึ่งในสองรายการในพื้นหลัง:

md5sum /path/to/file & sha256sum /path/to/file

หรือบันทึกผลลัพธ์ไปยังไฟล์ต่าง ๆ และรันหลายงานในเบื้องหลัง:

for file in *; do
    md5sum "$file" > "$file".md5 &
    sha256sum "$file" > "$file".sha &
done

ที่จะเปิดตัวmd5sumและsha256sumอินสแตนซ์มากเท่าที่คุณมีไฟล์และพวกเขาทั้งหมดจะทำงานในแบบคู่ขนาน, การบันทึกผลลัพธ์ของพวกเขาไปยังชื่อไฟล์ที่เกี่ยวข้อง แม้ว่าจะมีความระมัดระวัง แต่ก็อาจหนักขึ้นหากคุณมีไฟล์จำนวนมาก


1
ดูความคิดเห็นต่อมาร์โกความกังวลของฉันคือแม้ว่าคำสั่งจะขนานกัน แต่ดิสก์ที่ช้าก็สามารถเข้าถึงข้อมูลเดียวกันได้สองครั้ง
Lekensteyn

แต่การมีอยู่ของดิสก์แคชจะทำให้คุณกังวลโดยไม่จำเป็นหรือไม่?
Twinkles

2
@ ริ้วรอยในการอ้างอิง Lekensteyn ด้านบน "ปัญหาเกี่ยวกับวิธีการนั้นคือคำสั่งหนึ่งอาจเร็วกว่าอีกคำสั่งหนึ่งส่งผลให้ดิสก์แคชที่ถูกทำให้ว่างและเติมใหม่ในภายหลังด้วยข้อมูลเดียวกัน"
Matt Nordhoff

2
@MattNordhoff ยังมีอีกสิ่งหนึ่งที่ตัวกำหนดตารางเวลา I / O อัจฉริยะควรสังเกตและปรับให้เหมาะสม บางคนอาจคิดว่า: "มันยากขนาดไหนที่ I / O scheduler จะพิจารณาสถานการณ์นี้" แต่ด้วยสถานการณ์ที่แตกต่างกันมากพอที่ตัวกำหนดตารางเวลาของ I / O ควรคำนึงถึงมันจะกลายเป็นปัญหาอย่างหนัก ดังนั้นฉันจึงยอมรับว่าไม่ควรคิดว่าการแคชจะดูแลปัญหา
kasperd

1
สมมติว่า IO นั้นช้ากว่าเครื่องมือใด ๆ ที่เกี่ยวข้องอย่างมากเครื่องมือทั้งสองควรช้าลงด้วยความเร็วเดียวกันเนื่องจาก IO ดังนั้นหากเครื่องมือหนึ่งจัดการเพื่อรับบล็อกข้อมูลน้อยกว่าเครื่องมืออื่น ๆ เครื่องมืออื่น ๆ จะทันกับการคำนวณโดยใช้ข้อมูลในแคชดิสก์ นั่นคือทฤษฎีฉันชอบที่จะเห็นผลการทดลองพิสูจน์ได้ว่า ...
liori

3

ออกจาก curiousity ไม่ว่าจะเป็นสคริปต์แบบมัลติเธรดหลามจะช่วยลดเวลาทำงานผมสร้างนี้digest.pyสคริปต์ที่ใช้threading.Thread, threading.Queueและhashlibการคำนวณ hashes สำหรับหลายไฟล์

การใช้งาน Python แบบมัลติเธรดนั้นเร็วกว่าการใช้งานpeeกับ coreutils เล็กน้อย Java ในทางกลับกันคือ ... meh ผลลัพธ์มีอยู่ในข้อความยืนยันนี้ :

สำหรับการเปรียบเทียบสำหรับไฟล์ 2.3 GiB (min / avg / max / sd secs สำหรับ n = 10):

  • pee sha256sum md5sum <ไฟล์: 16.5 / 16.9 /17.4/.305
  • python3 digest.py -sha256 -md5 <ไฟล์: 13.7 / 15.0 /18.7/1.77
  • python2 digest.py -sha256 -md5 <ไฟล์: 13.7 / 15.9 18.7 1.64
  • jacksum -a sha256 + md5 -F '#CHECKSUM {i} #FILENAME': 32.7 / 37.1 /50/6.91

เอาต์พุตแฮชเข้ากันได้กับเอาต์พุตที่ผลิตโดย coreutils เนื่องจากความยาวขึ้นอยู่กับอัลกอริทึมการแปลงแป้นพิมพ์เครื่องมือนี้จึงไม่พิมพ์ การใช้งาน (สำหรับการเปรียบเทียบpeeถูกเพิ่มเข้าไปด้วย):

$ ./digest.py -sha256 -md5 digest.py
c217e5aa3c3f9cfaca0d40b1060f6233297a3a0d2728dd19f1de3b28454975f2  digest.py
b575edf6387888a68c93bf89291f611c  digest.py
$ ./digest.py -sha256 -md5 <digest.py
c217e5aa3c3f9cfaca0d40b1060f6233297a3a0d2728dd19f1de3b28454975f2  -
b575edf6387888a68c93bf89291f611c  -
$ pee sha256sum md5sum <digest.py
c217e5aa3c3f9cfaca0d40b1060f6233297a3a0d2728dd19f1de3b28454975f2  -
b575edf6387888a68c93bf89291f611c  -

ฉันจะแนะนำให้เปรียบเทียบpee "openssl sha256" "openssl md5" < fileแต่โดยความจริงแล้วฉันลองแล้วและมันก็ไม่ชนะ มันทำให้ช่องว่างแคบลง
Matt Nordhoff

1

Jacksum เป็นยูทิลิตี้อิสระที่ไม่เสียค่าใช้จ่ายและเป็นแพลตฟอร์มสำหรับการคำนวณและตรวจสอบ checksums, CRC และ hash (การย่อยข้อความ) รวมถึงการประทับเวลาของไฟล์ (คัดลอกมาจากหน้าคน jacksum )

เป็นไฟล์ขนาดใหญ่ที่รับรู้ได้สามารถประมวลผลขนาดไฟล์ได้สูงสุด 8 Exabytes (= 8,000,000,000 Gigabytes) เตรียมระบบปฏิบัติการของคุณตามลำดับระบบไฟล์ของคุณก็รับรู้ไฟล์ขนาดใหญ่เช่นกัน (คัดลอกมาจากhttp://www.jonelo.de/java/jacksum/ )

ตัวอย่างการใช้งาน:

jacksum -a md5+sha256 -F "#ALGONAME{i} (#FILENAME) = #CHECKSUM{i}" jacksum-testfile

ตัวอย่างผลลัพธ์:

md5 (jacksum-testfile) = d41d8cd98f00b204e9800998ecf8427e
sha256 (jacksum-testfile) = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

บน Ubuntu ให้รันคำสั่งapt-get install jacksumเพื่อรับค่า

หรือจะเลือกรหัสที่มาได้ที่


ในขณะที่สิ่งนี้ส่งออกเช็คซัมที่ถูกต้องโปรแกรม Java นี้จะคำนวณสองครั้งช้ากว่า coreutils ดูนี้กระทำข้อความ
Lekensteyn
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.