ฉันจะได้รับผลรวม MD5 ของเนื้อหาของไดเรกทอรีเป็นผลรวมเดียวได้อย่างไร


171

โปรแกรม md5sum ไม่ได้ให้ checksums สำหรับไดเรกทอรี ฉันต้องการรับการตรวจสอบ MD5 เดียวสำหรับเนื้อหาทั้งหมดของไดเรกทอรีรวมถึงไฟล์ในไดเรกทอรีย่อย นั่นคือการตรวจสอบรวมหนึ่งทำจากไฟล์ทั้งหมด มีวิธีทำเช่นนี้หรือไม่?

คำตอบ:


186

วิธีที่ถูกต้องขึ้นอยู่กับเหตุผลที่คุณถามว่า:

ตัวเลือกที่ 1: เปรียบเทียบข้อมูลเท่านั้น

หากคุณต้องการแฮชของเนื้อหาไฟล์ของทรีสิ่งนี้จะทำเคล็ดลับ:

$ find -s somedir -type f -exec md5sum {} \; | md5sum

ครั้งแรกนี้สรุปเนื้อหาไฟล์ทั้งหมดทีละรายการตามลำดับที่คาดเดาได้จากนั้นส่งรายการชื่อไฟล์และ MD5 แฮชที่จะแฮชตัวเองโดยให้ค่าเดียวที่จะเปลี่ยนเฉพาะเมื่อเนื้อหาของไฟล์ใดไฟล์หนึ่งในแผนภูมิเปลี่ยนไป

น่าเสียดายfind -sใช้งานได้กับ BSD find (1) ที่ใช้ใน macOS, FreeBSD, NetBSD และ OpenBSD เท่านั้น เพื่อให้ได้สิ่งที่เทียบเคียงได้กับระบบที่มี GNU หรือ SUS find (1) คุณต้องมีสิ่งที่น่าเกลียดสักหน่อย:

$ find somedir -type f -exec md5sum {} \; | sort -k 2 | md5sum

เราได้ถูกแทนที่ด้วยการเรียกร้องให้find -s บิตบอกว่ามันจะข้ามกัญชา MD5 จึงเพียงเรียงลำดับชื่อไฟล์ที่อยู่ในเขตที่ 2 ถึงจุดสิ้นสุดของเส้นโดย's คำนวณsort-k 2sort

มีจุดอ่อนในคำสั่งเวอร์ชันนี้ซึ่งจะทำให้สับสนถ้าคุณมีชื่อไฟล์ที่มีการขึ้นบรรทัดใหม่เพราะมันจะมีลักษณะเหมือนการsortโทรหลายบรรทัด find -sแตกต่างไม่ได้มีปัญหาที่เพราะ traversal findต้นไม้และการเรียงลำดับเกิดขึ้นภายในโปรแกรมเดียวกัน

ไม่ว่าในกรณีใดการเรียงลำดับเป็นสิ่งจำเป็นเพื่อหลีกเลี่ยงผลบวกปลอม: ระบบไฟล์ Unix / Linux ที่พบมากที่สุดไม่รักษารายชื่อไดเรกทอรีตามลำดับที่เสถียรและคาดการณ์ได้ คุณอาจไม่ได้ตระหนักถึงสิ่งนี้จากการใช้งานlsและเช่นนั้นซึ่งเรียงลำดับเนื้อหาไดเรกทอรีให้คุณอย่างเงียบ ๆ findโดยไม่ต้อง-sมีการsortเรียกหรือจะพิมพ์ไฟล์ในลำดับใดก็ตามที่ระบบไฟล์พื้นฐานส่งคืนซึ่งจะทำให้คำสั่งนี้ให้ค่าแฮชที่เปลี่ยนไปหากลำดับของไฟล์ที่กำหนดให้เป็นการเปลี่ยนแปลงอินพุต

คุณอาจต้องเปลี่ยนmd5sumคำสั่งเป็นmd5หรือฟังก์ชันแฮชอื่น ๆ หากคุณเลือกฟังก์ชันแฮชอื่นและต้องการรูปแบบที่สองของคำสั่งสำหรับระบบของคุณคุณอาจต้องปรับsortคำสั่งตามนั้น กับดักก็คือว่าบางโปรแกรมรวมข้อมูลไม่ได้เขียนชื่อไฟล์เลยตัวอย่างที่สำคัญเป็นsumโปรแกรมUnix เก่า

วิธีนี้ค่อนข้างไม่มีประสิทธิภาพการเรียกmd5sumN + 1 ครั้งโดยที่ N คือจำนวนไฟล์ในแผนผัง แต่นั่นเป็นค่าใช้จ่ายที่จำเป็นในการหลีกเลี่ยงการแฮชไฟล์และข้อมูลเมตาของไดเรกทอรี

ตัวเลือกที่ 2: เปรียบเทียบข้อมูลกับข้อมูลเมตา

หากคุณต้องการตรวจสอบว่ามีอะไรในทรีที่เปลี่ยนไปไม่ใช่แค่เนื้อหาไฟล์ขอtarให้แพ็คเนื้อหาไดเรกทอรีให้คุณแล้วส่งไปที่md5sum:

$ tar -cf - somedir | md5sum

เพราะtarยังเห็นการอนุญาตของไฟล์ความเป็นเจ้าของและอื่น ๆ สิ่งนี้จะตรวจจับการเปลี่ยนแปลงในสิ่งเหล่านั้นด้วยไม่ใช่แค่เปลี่ยนเนื้อหาของไฟล์

วิธีนี้เร็วกว่ามากเนื่องจากใช้การส่งผ่านต้นไม้เพียงครั้งเดียวและเรียกใช้โปรแกรมแฮชเพียงครั้งเดียวเท่านั้น

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

หากคุณพบว่าตัวเองได้รับผลบวกปลอมผมขอแนะนำให้ไปกับfind | cpioตัวเลือกในคำตอบที่กิลส์


7
ฉันคิดว่ามันเป็นที่ดีที่สุดที่จะนำทางไปยังไดเรกทอรีถูกเปรียบเทียบและใช้แทนfind . find somedirวิธีนี้ชื่อไฟล์จะเหมือนกันเมื่อมีการระบุรายละเอียดพา ธ ที่แตกต่างกัน นี้สามารถหากิน :-)
Abbafei

เราควรจัดเรียงไฟล์ด้วยหรือไม่
CMCDragonkai

@CMCDragonkai: คุณหมายถึงอะไร ในกรณีแรกเราจะเรียงลำดับรายชื่อไฟล์ ในกรณีที่สองเราตั้งใจไม่ทำเพราะส่วนหนึ่งของสิ่งที่เน้นในประโยคแรกคือลำดับของไฟล์ในไดเรกทอรีมีการเปลี่ยนแปลงดังนั้นคุณไม่ต้องการเรียงลำดับอะไรเลย
Warren Young

@WarrenYoung คุณช่วยอธิบายให้ละเอียดหน่อยได้ไหมว่าทำไมตัวเลือก 2 ถึงไม่ดีกว่าเสมอไป? ดูเหมือนว่าจะเร็วขึ้นง่ายขึ้นและข้ามแพลตฟอร์มมากขึ้น ในกรณีใดไม่ควรเลือก 1
Robin Winslow

ตัวเลือก 1 ทางเลือก: find somedir -type f -exec sh -c "openssl dgst -sha1 -binary {} | xxd -p" \; | sort | openssl dgst -sha1เพื่อละเว้นชื่อไฟล์ทั้งหมด (ควรทำงานกับ newlines)
windm

38

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

ข้อมูลและข้อมูลเมตา

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

ทางออกคือการเรียงลำดับชื่อไฟล์ก่อนเก็บถาวร หากชื่อไฟล์ของคุณไม่มีบรรทัดใหม่คุณสามารถเรียกใช้find | sortเพื่อแสดงรายการและเพิ่มลงในไฟล์เก็บถาวรตามลำดับนี้ ระวังบอกผู้จัดเก็บไม่ให้เรียกเก็บเงินคืนในไดเรกทอรี นี่คือตัวอย่างของ POSIX pax, GNU tar และ cpio:

find | LC_ALL=C sort | pax -w -d | md5sum
find | LC_ALL=C sort | tar -cf - -T - --no-recursion | md5sum
find | LC_ALL=C sort | cpio -o | md5sum

ชื่อและเนื้อหาเท่านั้นวิธีที่มีเทคโนโลยีต่ำ

หากคุณต้องการนำข้อมูลไฟล์เข้าบัญชีและไม่ใช่ข้อมูลเมตาคุณสามารถสร้างไฟล์เก็บถาวรที่มีเฉพาะเนื้อหาไฟล์เท่านั้น แต่ไม่มีเครื่องมือมาตรฐานสำหรับสิ่งนั้น แทนที่จะรวมเนื้อหาไฟล์คุณสามารถรวมแฮชของไฟล์ หากชื่อไฟล์ไม่มีการขึ้นบรรทัดใหม่และมีเพียงไฟล์และไดเรกทอรีปกติ (ไม่มีลิงก์สัญลักษณ์หรือไฟล์พิเศษ) นี่เป็นเรื่องง่าย แต่คุณจำเป็นต้องดูแลบางสิ่ง:

{ export LC_ALL=C;
  find -type f -exec wc -c {} \; | sort; echo;
  find -type f -exec md5sum {} + | sort; echo;
  find . -type d | sort; find . -type d | sort | md5sum;
} | md5sum

เรารวมรายชื่อไดเรกทอรีไว้นอกเหนือจากรายการ checksums ด้วยเช่นกันไดเรกทอรีที่ว่างเปล่าจะมองไม่เห็น รายการไฟล์จะถูกจัดเรียง (ในสถานที่เฉพาะที่ทำซ้ำได้ - ขอบคุณ Peter.O สำหรับเตือนความจำฉัน) echoแยกสองส่วนออกจากกัน (หากไม่มีสิ่งนี้คุณสามารถสร้างไดเร็กตอรี่ว่าง ๆ ที่มีชื่อคล้ายกับmd5sumเอาต์พุตที่อาจส่งผ่านไฟล์ธรรมดาได้) เรายังรวมถึงรายชื่อของขนาดไฟล์เพื่อหลีกเลี่ยงการโจมตีระยะเวลาในนามสกุล

โดยวิธีการ MD5 จะเลิก หากมีให้พิจารณาใช้ SHA-2 หรืออย่างน้อย SHA-1

ชื่อและข้อมูลรองรับการขึ้นบรรทัดใหม่ในชื่อ

นี่คือความแตกต่างของรหัสด้านบนที่อาศัยเครื่องมือ GNU เพื่อแยกชื่อไฟล์ด้วย null null สิ่งนี้อนุญาตให้ชื่อไฟล์มีการขึ้นบรรทัดใหม่ ยูทิลิตี้การแยกย่อยของ GNU อ้างถึงอักขระพิเศษในผลลัพธ์ดังนั้นจึงไม่มีบรรทัดใหม่ที่ไม่ชัดเจน

{ export LC_ALL=C;
  du -0ab | sort -z; # file lengths, including directories (with length 0)
  echo | tr '\n' '\000'; # separator
  find -type f -exec sha256sum {} + | sort -z; # file hashes
  echo | tr '\n' '\000'; # separator
  echo "End of hashed data."; # End of input marker
} | sha256sum

แนวทางที่แข็งแกร่งยิ่งขึ้น

ต่อไปนี้เป็นสคริปต์ Python ที่ผ่านการทดสอบเพียงเล็กน้อยซึ่งจะสร้างแฮชที่อธิบายถึงลำดับชั้นของไฟล์ จะนำไดเรกทอรีและเนื้อหาไฟล์ไปยังบัญชีและละเว้นลิงก์สัญลักษณ์และไฟล์อื่น ๆ และส่งคืนข้อผิดพลาดร้ายแรงหากไฟล์ใด ๆ ไม่สามารถอ่านได้

#! /usr/bin/env python
import hashlib, hmac, os, stat, sys
## Return the hash of the contents of the specified file, as a hex string
def file_hash(name):
    f = open(name)
    h = hashlib.sha256()
    while True:
        buf = f.read(16384)
        if len(buf) == 0: break
        h.update(buf)
    f.close()
    return h.hexdigest()
## Traverse the specified path and update the hash with a description of its
## name and contents
def traverse(h, path):
    rs = os.lstat(path)
    quoted_name = repr(path)
    if stat.S_ISDIR(rs.st_mode):
        h.update('dir ' + quoted_name + '\n')
        for entry in sorted(os.listdir(path)):
            traverse(h, os.path.join(path, entry))
    elif stat.S_ISREG(rs.st_mode):
        h.update('reg ' + quoted_name + ' ')
        h.update(str(rs.st_size) + ' ')
        h.update(file_hash(path) + '\n')
    else: pass # silently symlinks and other special files
h = hashlib.sha256()
for root in sys.argv[1:]: traverse(h, root)
h.update('end\n')
print h.hexdigest()

ตกลงใช้งานได้ขอบคุณ แต่มีวิธีใดที่จะทำได้โดยไม่รวมข้อมูลเมตาใด ๆ ตอนนี้ฉันต้องการเพียงเนื้อหาจริง

วิธีการเกี่ยวกับLC_ALL=C sortการตรวจสอบจากสภาพแวดล้อมที่แตกต่างกัน ... (+ 1 btw)
Peter.O

คุณทำโปรแกรม Python ทั้งหมดสำหรับเรื่องนี้? ขอบคุณ! นี่เป็นสิ่งที่เกินความคาดหมาย :-) อย่างไรก็ตามฉันจะตรวจสอบวิธีการเหล่านี้รวมถึงตัวเลือกใหม่ 1 ของ Warren

คำตอบที่ดี. การตั้งค่าการเรียงลำดับด้วยLC_ALL=Cเป็นสิ่งสำคัญหากใช้กับเครื่องและระบบปฏิบัติการหลายเครื่อง
Davor Cubranic

อะไรcpio -o -หมายความว่าอย่างไร cpio ใช้ stdin / out เป็นค่าเริ่มต้นหรือไม่? GNU cpio 2.12 ผลิตcpio: Too many arguments
ม.ค. Tojnar

12

มีลักษณะที่md5deep คุณสมบัติบางอย่างของ md5deep ที่คุณอาจสนใจ:

การดำเนินการซ้ำ - md5deep สามารถตรวจสอบทรีไดเรกทอรีทั้งหมด นั่นคือคำนวณ MD5 สำหรับทุกไฟล์ในไดเรกทอรีและสำหรับทุกไฟล์ในทุกไดเรกทอรีย่อย

โหมดเปรียบเทียบ - md5deep สามารถยอมรับรายการของแฮชที่รู้จักและเปรียบเทียบกับชุดของไฟล์อินพุต โปรแกรมสามารถแสดงไฟล์อินพุตเหล่านั้นที่ตรงกับรายการของแฮชที่รู้จักหรือไฟล์ที่ไม่ตรงกัน

...


ดีมาก แต่ใช้งานไม่ได้พูดว่า.../foo: Is a directoryอะไรให้
Camilo Martin

3
ด้วยตัวของมันเอง md5deep ไม่สามารถแก้ปัญหาของ OP ได้เนื่องจากมันไม่ได้พิมพ์ md5sum ที่รวมไว้มันแค่พิมพ์ md5sum สำหรับแต่ละไฟล์ในไดเรกทอรี ที่กล่าวว่าคุณสามารถ md5sum การส่งออกของ md5deep - ไม่ค่อนข้างสิ่ง OP ต้องการ แต่อยู่ใกล้! เช่นสำหรับไดเรกทอรีปัจจุบัน: md5deep -r -l -j0 . | md5sum(โดยที่-rเรียกซ้ำ-lหมายถึง "ใช้พา ธ สัมพัทธ์" เพื่อให้พา ธ สัมบูรณ์ของไฟล์ไม่รบกวนเมื่อพยายามเปรียบเทียบเนื้อหาของสองไดเรกทอรีและ-j0ใช้ 1 เธรดเพื่อป้องกันการไม่กำหนด ไปที่ md5sums แต่ละรายการจะถูกส่งคืนในคำสั่งซื้อที่ต่างกัน)
Stevie

วิธีที่จะไม่สนใจบางไฟล์ / ไดเรกทอรีในเส้นทาง?
Sandeepan Nath

9

หากเป้าหมายของคุณเพียงเพื่อค้นหาความแตกต่างระหว่างสองไดเรกทอรีให้ลองใช้ diff

ลองสิ่งนี้:

diff -qr dir1 dir2

ใช่มันมีประโยชน์เช่นกัน ฉันคิดว่าคุณหมายถึง dir1 dir2 ในคำสั่งนั้น

1
ปกติฉันไม่ใช้ GUIs เมื่อฉันสามารถหลีกเลี่ยงได้ แต่สำหรับไดเร็กตอรี่ที่แตกต่าง kdiff3นั้นยอดเยี่ยมและใช้ได้กับหลายแพลตฟอร์ม
sinelaw

มีการรายงานไฟล์ที่ต่างกันด้วยคำสั่งนี้
Serge Stroobandt

7

คุณสามารถแฮชไฟล์ทุกไฟล์ซ้ำแล้วทำการแฮชข้อความผลลัพธ์:

> md5deep -r -l . | sort | md5sum
d43417958e47758c6405b5098f151074 *-

ต้องมีmd5deep


1
แทนที่จะmd5deepใช้hashdeepบน Ubuntu 16.04 เพราะแพ็คเกจ md5deep เป็นเพียงหุ่นจำลองสำหรับ hashdeep
palik

1
ฉันลอง hashdeep แล้ว มันออก hashes ไม่เพียง แต่ยังรวมถึงส่วนหัวบางส่วนซึ่งเป็นเส้นทางปัจจุบันของคุณและ## Invoked from: /home/myuser/dev/ ## $ hashdeep -s -r -l ~/folder/สิ่งนี้จะต้องเรียงลำดับดังนั้นแฮชสุดท้ายจะแตกต่างกันหากคุณเปลี่ยนโฟลเดอร์ปัจจุบันหรือบรรทัดคำสั่ง
truf

3

ไฟล์เนื้อหาเท่านั้นไม่รวมชื่อไฟล์

ฉันต้องการเวอร์ชันที่ตรวจสอบชื่อไฟล์เพียงเพราะเนื้อหาอยู่ในไดเรกทอรีที่ต่างกัน

รุ่นนี้ (คำตอบของ Warren Young)ช่วยได้มาก แต่รุ่นของฉันmd5sumส่งออกชื่อไฟล์ (สัมพันธ์กับเส้นทางที่ฉันเรียกใช้คำสั่งจาก) และชื่อโฟลเดอร์แตกต่างกันดังนั้นแม้ว่าการตรวจสอบไฟล์แต่ละไฟล์จะตรงกับการตรวจสอบขั้นสุดท้าย 'T

ในการแก้ไขนั้นในกรณีของฉันฉันแค่ต้องตัดชื่อไฟล์ออกจากแต่ละบรรทัดของfindเอาต์พุต (เลือกเฉพาะคำแรกที่คั่นด้วยช่องว่างโดยใช้cut):

find -s somedir -type f -exec md5sum {} \; | cut -d" " -f1 | md5sum

คุณอาจต้องเรียงลำดับการตรวจสอบรวมทั้งเพื่อรับรายการที่ทำซ้ำได้
eckes

3

วิธีแก้ปัญหา :

$ pip install checksumdir
$ checksumdir -a md5 assets/js
981ac0bc890de594a9f2f40e00f13872
$ checksumdir -a sha1 assets/js
88cd20f115e31a1e1ae381f7291d0c8cd3b92fad

ใช้งานได้ง่ายและรวดเร็วขึ้นวิธีการแก้ปัญหาแล้วทุบตีสคริปต์

ดูเอกสาร: https://pypi.python.org/pypi/checksumdir/1.0.5


หากคุณไม่มี pip คุณอาจต้องติดตั้งด้วย yum -y ติดตั้ง python-pip (หรือ dnf / apt-get)
DmitrySemenov

3

nix-hashจากผู้จัดการแพคเกจระวัง

คำสั่ง nix-hash คำนวณแฮชการเข้ารหัสของเนื้อหาของแต่ละพา ธ และพิมพ์ลงบนเอาต์พุตมาตรฐาน โดยค่าเริ่มต้นมันคำนวณ MD5 แฮช แต่อัลกอริทึมแฮชอื่น ๆ ที่มีอยู่เช่นกัน แฮชจะพิมพ์เป็นเลขฐานสิบหก

แฮชถูกคำนวณบนการทำให้เป็นอนุกรมของแต่ละพา ธ : ดัมพ์ของทรีของระบบไฟล์ที่รูทที่พา ธ สิ่งนี้อนุญาตให้ไดเรกทอรีและ symlink ถูกแฮชรวมถึงไฟล์ปกติ ดัมพ์อยู่ในรูปแบบ NAR ที่สร้างโดย nix-store --dump ดังนั้นเส้นทาง nix-hash ให้ผลตอบแทนแฮชการเข้ารหัสเช่นเดียวกับ nix-store --dump path | md5sum


2

ฉันใช้ส่วนย่อยนี้สำหรับปริมาณปานกลาง :

find . -xdev -type f -print0 | LC_COLLATE=C sort -z | xargs -0 cat | md5sum -

และอันนี้สำหรับXXXL :

find . -xdev -type f -print0 | LC_COLLATE=C sort -z | xargs -0 tail -qc100 | md5sum -


อะไร-xdevธงทำอย่างไร
czerasz

มันขอให้คุณพิมพ์: man findและอ่านคู่มือที่ดี;)
poige

จุดดี :-). -xdev Don't descend directories on other filesystems.
czerasz

1
โปรดทราบว่าการดำเนินการนี้จะละเว้นไฟล์ใหม่ที่ว่างเปล่า (เช่นถ้าคุณแตะไฟล์)
RonJohn

มีหลายกรณีที่สิ่งนี้จะให้ผล md5sum เดียวกันกับโครงสร้างไฟล์และไดเรกทอรีที่แตกต่างอย่างสิ้นเชิง การเปลี่ยนชื่อไฟล์และไดเรกทอรีจะไม่เปลี่ยนแปลงเลยหากไม่เปลี่ยนลำดับการเรียงไฟล์ ดังนั้นฉันจะไม่แนะนำวิธีการนี้
Hans-Peter Störr

2

การตรวจสอบต้นไม้ที่ดีคือ tree-id ของ Git

ขออภัยไม่มีเครื่องมือแบบสแตนด์อโลนที่สามารถทำได้ (อย่างน้อยฉันก็ไม่รู้) แต่ถ้าคุณมี Git คุณสามารถแกล้งตั้งค่าพื้นที่เก็บข้อมูลใหม่และเพิ่มไฟล์ที่คุณต้องการตรวจสอบไปยังดัชนี

สิ่งนี้ช่วยให้คุณสามารถสร้างแฮชทรี (ที่ทำซ้ำได้) ซึ่งมีเฉพาะเนื้อหาชื่อไฟล์และโหมดไฟล์ที่ลดขนาด (ปฏิบัติการ)


2

จากการติดตามคำตอบที่ยอดเยี่ยมนี้หากคุณพบว่าตัวเองต้องการเร่งการคำนวณผลรวมตรวจสอบสำหรับไดเรกทอรีขนาดใหญ่ให้ลองใช้GNU Parallel :

find -s somedir -type f | parallel -k -n 100 md5 {} | md5

(นี่คือการใช้ Mac ด้วยmd5แทนที่ตามที่จำเป็น)

การ-kตั้งค่าสถานะเป็นสิ่งสำคัญที่แนะนำparallelให้รักษาลำดับมิฉะนั้นผลรวมโดยรวมสามารถเปลี่ยนเรียกใช้เพื่อเรียกใช้แม้ว่าไฟล์จะเหมือนกันทั้งหมด -n 100บอกให้รันแต่ละอินสแตนซ์ที่md5มีอาร์กิวเมนต์ 100 ตัวนี่เป็นพารามิเตอร์ที่คุณสามารถปรับแต่งเพื่อให้ได้เวลาการทำงานที่ดีที่สุด ดูการ-Xตั้งค่าสถานะของparallel(แม้ว่าในกรณีส่วนบุคคลของฉันที่ทำให้เกิดข้อผิดพลาด)


1

สคริปต์ที่มีการทดสอบอย่างดีและสนับสนุนจำนวนของการดำเนินงานรวมทั้งการหาที่ซ้ำกันทำรถทั้งข้อมูลและเมตาดาต้าแสดงเพิ่มเติมรวมทั้งการเปลี่ยนแปลงและการลบที่คุณอาจชอบลายนิ้วมือ

ลายนิ้วมือในขณะนี้ไม่ได้สร้าง checksum เดียวสำหรับไดเรกทอรี แต่ไฟล์ transcript ซึ่งรวมถึง checksums สำหรับไฟล์ทั้งหมดในไดเรกทอรีนั้น

fingerprint analyze

สิ่งนี้จะสร้างindex.fingerprintในไดเรกทอรีปัจจุบันซึ่งรวมถึง checksums ชื่อไฟล์และขนาดไฟล์ โดยค่าเริ่มต้นจะใช้ทั้งสองและMD5SHA1.256

ในอนาคตฉันหวังว่าจะเพิ่มการสนับสนุนสำหรับต้นไม้ Merkle ลงในลายนิ้วมือซึ่งจะให้การตรวจสอบระดับบนสุดเพียงครั้งเดียว ตอนนี้คุณต้องเก็บไฟล์นั้นไว้เพื่อทำการตรวจสอบ


1

ฉันไม่ต้องการโปรแกรมปฏิบัติการใหม่หรือโซลูชันที่ไม่น่าสนใจดังนั้นนี่คือสิ่งที่ฉันต้องทำ:

#!/bin/sh
# md5dir.sh by Camilo Martin, 2014-10-01.
# Give this a parameter and it will calculate an md5 of the directory's contents.
# It only takes into account file contents and paths relative to the directory's root.
# This means that two dirs with different names and locations can hash equally.

if [[ ! -d "$1" ]]; then
    echo "Usage: md5dir.sh <dir_name>"
    exit
fi

d="$(tr '\\' / <<< "$1" | tr -s / | sed 's-/$--')"
c=$((${#d} + 35))
find "$d" -type f -exec md5sum {} \; | cut -c 1-33,$c- | sort | md5sum | cut -c 1-32

0

วิธีการที่แข็งแกร่งและสะอาด

  • สิ่งแรกที่ไม่หมูหน่วยความจำที่มีอยู่ ! แฮชไฟล์เป็นกลุ่มแทนที่จะป้อนไฟล์ทั้งหมด
  • วิธีการที่แตกต่างกันสำหรับความต้องการ / วัตถุประสงค์ที่แตกต่างกัน (ด้านล่างทั้งหมดหรือเลือกสิ่งที่เคยใช้):
    • แฮชเฉพาะชื่อรายการของรายการทั้งหมดในต้นไม้ไดเรกทอรี
    • แฮชเนื้อหาไฟล์ของรายการทั้งหมด (ทิ้งเมตาไลต์, หมายเลขไอโหนด, ctime, atime, mtime, ขนาด ฯลฯ คุณจะได้แนวคิด)
    • สำหรับลิงก์สัญลักษณ์เนื้อหาของมันคือชื่อผู้อ้างอิง แฮชหรือเลือกที่จะข้าม
    • ติดตามหรือไม่ทำตาม (ชื่อที่แก้ไขแล้ว) ลิงก์ในขณะที่แฮชเนื้อหาของรายการ
    • หากเป็นไดเรกทอรีเนื้อหานั้นเป็นเพียงรายการไดเรกทอรี ในขณะที่การสำรวจซ้ำพวกเขาจะถูกแฮชในที่สุด แต่ควรชื่อรายการไดเรกทอรีของระดับนั้นถูกแฮชเพื่อแท็กไดเรกทอรีนี้หรือไม่ มีประโยชน์ในการใช้งานกรณีที่ต้องการแฮชเพื่อระบุการเปลี่ยนแปลงอย่างรวดเร็วโดยไม่ต้องท่องลึกเพื่อแฮชเนื้อหา ตัวอย่างจะเป็นการเปลี่ยนชื่อไฟล์ แต่เนื้อหาที่เหลือยังคงเหมือนเดิมและเป็นไฟล์ที่มีขนาดใหญ่พอสมควร
    • จัดการไฟล์ขนาดใหญ่ได้ดี (โปรดคำนึงถึง RAM อีกครั้ง)
    • จัดการแผนผังไดเรกทอรีที่มีความลึกมาก ๆ
    • จัดการกับชื่อไฟล์ที่ไม่ได้มาตรฐาน
    • วิธีดำเนินการกับไฟล์ที่เป็นซ็อกเก็ต, ไปป์ / FIFO, อุปกรณ์บล็อก, อุปกรณ์ถ่าน? ต้องแฮชพวกเขาด้วยเช่นกัน?
    • อย่าอัปเดตเวลาเข้าถึงของรายการใด ๆ ในขณะที่แวะผ่านเพราะจะเป็นผลข้างเคียงและตอบโต้การผลิต (ใช้งานง่าย?) สำหรับกรณีการใช้งานบางอย่าง

นี่คือสิ่งที่ฉันมีอยู่ด้านบนหัวของฉันคนใดคนหนึ่งที่ใช้เวลาในการทำงานเกี่ยวกับเรื่องนี้จริง ๆ จะได้รับกรณี gotchas และมุมอื่น ๆ

นี่คือเครื่องมือ (ข้อจำกัดความรับผิดชอบ: ฉันเป็นผู้สนับสนุน) dtreetrawl , หน่วยความจำที่เบามากซึ่งกล่าวถึงกรณีส่วนใหญ่อาจจะค่อนข้างหยาบรอบ ๆ ขอบ แต่ก็มีประโยชน์มาก

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

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

Application Options:
  -t, --terse               Produce a terse output; parsable.
  -d, --delim=:             Character or string delimiter/separator for terse output(default ':')
  -l, --max-level=N         Do not traverse tree beyond N level(s)
  --hash                    Hash the files to produce checksums(default is MD5).
  -c, --checksum=md5        Valid hashing algorithms: md5, sha1, sha256, sha512.
  -s, --hash-symlink        Include symbolic links' referent name while calculating the root checksum
  -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

ตัวอย่างผลลัพธ์ที่เป็นมิตรของมนุษย์:

...
... //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

คำแนะนำทั่วไปยินดีต้อนรับเสมอ แต่คำตอบที่ดีที่สุดนั้นเจาะจงและใช้รหัสตามความเหมาะสม หากคุณมีประสบการณ์ในการใช้เครื่องมือที่คุณอ้างถึงโปรดรวมไว้ด้วย
bu5hman

@ bu5hman แน่นอน! ฉันไม่ค่อยสบายใจที่จะพูดว่า (ดูถูก?) เพิ่มเติมเกี่ยวกับวิธีการทำงานที่ดีเนื่องจากฉันมีส่วนร่วมในการพัฒนา
หก -k

0

ทำทีละไฟล์สำหรับแต่ละไดเรกทอรี

# Calculating
find dir1 | xargs md5sum > dir1.md5
find dir2 | xargs md5sum > dir2.md5
# Comparing (and showing the difference)
paste <(sort -k2 dir1.md5) <(sort -k2 dir2.md5) | awk '$1 != $3'

0

รูปแบบการโยกย้ายไปยัง POSIX เก็บถาวรส่งผลกระทบต่อการตรวจสอบตาม GNU Tar

คำตอบนี้มีจุดประสงค์เพื่อเป็นการปรับปรุงเพิ่มเติมสำหรับวิธีการใช้ Tar ส่งออกเพื่อแฮชเนื้อหาของไดเรกทอรีตามที่เสนอ (เหนือสิ่งอื่นใด) ในคำตอบที่ยอดเยี่ยมของWarren YoungและGillesเมื่อไม่นานมานี้

ตั้งแต่นั้นมาอย่างน้อย openSUSE (ตั้งแต่ปล่อย 12.2) การเปลี่ยนแปลงรูปแบบของพวกเขาเริ่มต้น GNU Tar จาก"GNU tar 1.13.x รูปแบบ"ไป (เล็กน้อย) ที่เหนือกว่า"POSIX 1,003.1-2,001 (ท่าน) รูปแบบ" นอกจากนี้ต้นน้ำ (ในบรรดาผู้พัฒนา GNU Tar) พวกเขาหารือกันเพื่อทำการโยกย้ายเดียวกันดูตัวอย่างย่อหน้าสุดท้ายในหน้านี้ของคู่มือGNU Tar :

รูปแบบเริ่มต้นสำหรับ GNU tar ถูกกำหนดในเวลารวบรวม คุณสามารถตรวจสอบได้โดยเรียกใช้tar --helpและตรวจสอบบรรทัดสุดท้ายของผลลัพธ์ โดยปกติ tar GNU มีการกำหนดให้สร้างคลังข้อมูลในgnuรูปแบบ posixแต่รุ่นในอนาคตจะเปลี่ยนไป

(หน้านี้ยังให้ความเห็นที่ดีเกี่ยวกับรูปแบบการเก็บถาวรต่าง ๆ ที่มีใน GNU Tar)

ในกรณีของเราที่เราเก็บเนื้อหาไดเรกทอรีและแฮชผลลัพธ์และโดยไม่ต้องดำเนินการใด ๆ เฉพาะการเปลี่ยนแปลงจากรูปแบบ GNU เป็น POSIX มีผลต่อไปนี้:

  • แม้จะมีเนื้อหาไดเรกทอรีเหมือนกันการตรวจสอบผลลัพธ์จะแตกต่างกัน

  • แม้จะมีเนื้อหาไดเรกทอรีเหมือนกันการตรวจสอบผลลัพธ์จะแตกต่างจากการเรียกใช้เพื่อเรียกใช้หากมีการใช้ส่วนหัว pax เริ่มต้น

สิ่งหลังมาจากข้อเท็จจริงที่ว่ารูปแบบ POSIX (pax) รวมส่วนหัว pax แบบขยายซึ่งถูกกำหนดโดยสตริงรูปแบบที่เป็นค่าเริ่มต้น%d/PaxHeaders.%p/%fใน GNU Tar ภายในสตริงนี้ตัวระบุ%pจะถูกแทนที่ด้วย ID กระบวนการของกระบวนการสร้าง Tar ซึ่งแน่นอนว่าแตกต่างจากการรันเพื่อรัน ดูส่วนนี้ของคู่มือGNU Tarและโดยเฉพาะในรายละเอียดนี้

ตอนนี้ย้อนหลังไปปี 2019-03-28 มีความมุ่งมั่นที่ได้รับการยอมรับซึ่งแก้ปัญหานี้ได้

ดังนั้นเพื่อให้สามารถใช้ GNU Tar ต่อไปในกรณีการใช้งานที่กำหนดฉันสามารถแนะนำตัวเลือกอื่น ๆ ต่อไปนี้:

  • ใช้ตัวเลือก Tar --format=gnuเพื่อบอกให้ Tar ทราบอย่างชัดเจนเพื่อสร้างไฟล์เก็บถาวรในรูปแบบ "เก่า" นี่เป็นข้อบังคับในการตรวจสอบ checksums "เก่า"

  • ใช้รูปแบบ POSIX ใหม่ --pax-option="exthdr.name=%d/PaxHeaders/%f"แต่ระบุอย่างชัดเจนส่วนหัวของท่านเหมาะสมเช่นโดยการ อย่างไรก็ตามสิ่งนี้จะทำลายความเข้ากันได้ย้อนหลังกับการตรวจสอบ "เก่า"

นี่เป็นส่วนย่อยของรหัส Bash ที่ฉันใช้เป็นประจำเพื่อคำนวณผลรวมตรวจสอบเนื้อหาไดเรกทอรีรวมถึงข้อมูลเมตา:

( export LC_ALL=C
  find <paths> ! -type s -print0 |
  sort -z |
  tar cp --format=gnu --numeric-owner \
         --atime-preserve \
         --no-recursion --null --files-from - |
  md5sum --binary; )

ในที่นี้<paths>จะถูกแทนที่ด้วยรายการที่คั่นด้วยช่องว่างของเส้นทางของไดเรกทอรีทั้งหมดที่ฉันต้องการที่จะครอบคลุมโดยการตรวจสอบ วัตถุประสงค์ของการใช้โลแคล C การแยกชื่อไฟล์ว่างของไบต์และการใช้การค้นหาและการเรียงลำดับเพื่อให้ได้คำสั่งที่เป็นอิสระต่อระบบไฟล์ของไฟล์ในไฟล์เก็บถาวรมีการกล่าวถึงอย่างเพียงพอในคำตอบอื่น ๆ

วงเล็บที่อยู่โดยรอบจะเก็บการLC_ALLตั้งค่าไว้ในเชลล์ย่อย

นอกจากนี้ฉันใช้นิพจน์! -type sด้วยfindเพื่อหลีกเลี่ยงคำเตือนจาก Tar ที่เกิดขึ้นหากไฟล์ซ็อกเก็ตเป็นส่วนหนึ่งของเนื้อหาไดเรกทอรี: GNU Tar ไม่ได้เก็บถาวรซ็อกเก็ต หากคุณต้องการรับการแจ้งเตือนเกี่ยวกับซ็อกเก็ตที่ข้ามให้ปล่อยให้นิพจน์นั้นหายไป

ฉันใช้--numeric-ownerกับ Tar เพื่อให้สามารถตรวจสอบการตรวจสอบในภายหลังแม้ในระบบที่ไม่รู้จักเจ้าของไฟล์ทั้งหมด

--atime-preserveตัวเลือกสำหรับการ Tar ถูกละไว้ดีกว่าถ้าใด ๆ ของ<paths>การโกหกในการติดตั้งอุปกรณ์ที่อ่านอย่างเดียว มิฉะนั้นคุณจะได้รับการเตือนสำหรับไฟล์แต่ละไฟล์ที่มีการบันทึกเวลาการเข้าถึง Tar ไม่สามารถกู้คืนได้ สำหรับการเปิดใช้งานการเขียน<paths>ฉันใช้ตัวเลือกนี้ดีเพื่อรักษาเวลาการเข้าถึงในไดเรกทอรีที่แฮช

กลาสีเรือตัวเลือก--no-recursionซึ่งถูกใช้อยู่แล้วในข้อเสนอ Gillesป้องกันต้าจากเชื้อสายซ้ำลงในไดเรกทอรีด้วยตัวเองและการดำเนินงานแทนไฟล์โดยไฟล์ในสิ่งที่จะได้รับการเลี้ยงดูจากที่เรียงลำดับfindการส่งออก

และในที่สุดก็ไม่เป็นความจริงที่ผมใช้md5sum: sha256sumที่จริงผมใช้


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