โปรแกรม md5sum ไม่ได้ให้ checksums สำหรับไดเรกทอรี ฉันต้องการรับการตรวจสอบ MD5 เดียวสำหรับเนื้อหาทั้งหมดของไดเรกทอรีรวมถึงไฟล์ในไดเรกทอรีย่อย นั่นคือการตรวจสอบรวมหนึ่งทำจากไฟล์ทั้งหมด มีวิธีทำเช่นนี้หรือไม่?
โปรแกรม md5sum ไม่ได้ให้ checksums สำหรับไดเรกทอรี ฉันต้องการรับการตรวจสอบ MD5 เดียวสำหรับเนื้อหาทั้งหมดของไดเรกทอรีรวมถึงไฟล์ในไดเรกทอรีย่อย นั่นคือการตรวจสอบรวมหนึ่งทำจากไฟล์ทั้งหมด มีวิธีทำเช่นนี้หรือไม่?
คำตอบ:
วิธีที่ถูกต้องขึ้นอยู่กับเหตุผลที่คุณถามว่า:
หากคุณต้องการแฮชของเนื้อหาไฟล์ของทรีสิ่งนี้จะทำเคล็ดลับ:
$ 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 2
sort
มีจุดอ่อนในคำสั่งเวอร์ชันนี้ซึ่งจะทำให้สับสนถ้าคุณมีชื่อไฟล์ที่มีการขึ้นบรรทัดใหม่เพราะมันจะมีลักษณะเหมือนการsort
โทรหลายบรรทัด find -s
แตกต่างไม่ได้มีปัญหาที่เพราะ traversal find
ต้นไม้และการเรียงลำดับเกิดขึ้นภายในโปรแกรมเดียวกัน
ไม่ว่าในกรณีใดการเรียงลำดับเป็นสิ่งจำเป็นเพื่อหลีกเลี่ยงผลบวกปลอม: ระบบไฟล์ Unix / Linux ที่พบมากที่สุดไม่รักษารายชื่อไดเรกทอรีตามลำดับที่เสถียรและคาดการณ์ได้ คุณอาจไม่ได้ตระหนักถึงสิ่งนี้จากการใช้งานls
และเช่นนั้นซึ่งเรียงลำดับเนื้อหาไดเรกทอรีให้คุณอย่างเงียบ ๆ find
โดยไม่ต้อง-s
มีการsort
เรียกหรือจะพิมพ์ไฟล์ในลำดับใดก็ตามที่ระบบไฟล์พื้นฐานส่งคืนซึ่งจะทำให้คำสั่งนี้ให้ค่าแฮชที่เปลี่ยนไปหากลำดับของไฟล์ที่กำหนดให้เป็นการเปลี่ยนแปลงอินพุต
คุณอาจต้องเปลี่ยนmd5sum
คำสั่งเป็นmd5
หรือฟังก์ชันแฮชอื่น ๆ หากคุณเลือกฟังก์ชันแฮชอื่นและต้องการรูปแบบที่สองของคำสั่งสำหรับระบบของคุณคุณอาจต้องปรับsort
คำสั่งตามนั้น กับดักก็คือว่าบางโปรแกรมรวมข้อมูลไม่ได้เขียนชื่อไฟล์เลยตัวอย่างที่สำคัญเป็นsum
โปรแกรมUnix เก่า
วิธีนี้ค่อนข้างไม่มีประสิทธิภาพการเรียกmd5sum
N + 1 ครั้งโดยที่ N คือจำนวนไฟล์ในแผนผัง แต่นั่นเป็นค่าใช้จ่ายที่จำเป็นในการหลีกเลี่ยงการแฮชไฟล์และข้อมูลเมตาของไดเรกทอรี
หากคุณต้องการตรวจสอบว่ามีอะไรในทรีที่เปลี่ยนไปไม่ใช่แค่เนื้อหาไฟล์ขอtar
ให้แพ็คเนื้อหาไดเรกทอรีให้คุณแล้วส่งไปที่md5sum
:
$ tar -cf - somedir | md5sum
เพราะtar
ยังเห็นการอนุญาตของไฟล์ความเป็นเจ้าของและอื่น ๆ สิ่งนี้จะตรวจจับการเปลี่ยนแปลงในสิ่งเหล่านั้นด้วยไม่ใช่แค่เปลี่ยนเนื้อหาของไฟล์
วิธีนี้เร็วกว่ามากเนื่องจากใช้การส่งผ่านต้นไม้เพียงครั้งเดียวและเรียกใช้โปรแกรมแฮชเพียงครั้งเดียวเท่านั้น
เช่นเดียวกับfind
วิธีการที่กล่าวมาแล้วข้างต้นtar
กำลังจะประมวลผลชื่อไฟล์ตามลำดับที่ระบบไฟล์อ้างอิงส่งคืน อาจเป็นไปได้ว่าในใบสมัครของคุณคุณสามารถมั่นใจได้ว่าคุณจะไม่ทำให้สิ่งนี้เกิดขึ้น ฉันสามารถนึกถึงรูปแบบการใช้งานที่แตกต่างกันอย่างน้อยสามรูปแบบซึ่งน่าจะเป็นเช่นนั้น (ฉันจะไม่แสดงรายการพวกเขาเพราะเรากำลังเข้าสู่อาณาเขตพฤติกรรมที่ไม่ระบุระบบไฟล์แต่ละระบบอาจแตกต่างกันได้ที่นี่แม้จากระบบปฏิบัติการเวอร์ชันหนึ่งไปยังรุ่นถัดไป)
หากคุณพบว่าตัวเองได้รับผลบวกปลอมผมขอแนะนำให้ไปกับfind | cpio
ตัวเลือกในคำตอบที่กิลส์
find somedir -type f -exec sh -c "openssl dgst -sha1 -binary {} | xxd -p" \; | sort | openssl dgst -sha1
เพื่อละเว้นชื่อไฟล์ทั้งหมด (ควรทำงานกับ newlines)
การตรวจสอบจะต้องมีการแสดงที่กำหนดและชัดเจนของไฟล์เป็นสตริง กำหนดหมายความว่าถ้าคุณใส่ไฟล์เดียวกันในสถานที่เดียวกันคุณจะได้รับผลลัพธ์เดียวกัน หมายความว่าสองชุดไฟล์ที่แตกต่างกันมีรูปแบบที่ต่างกัน
การสร้างไฟล์เก็บถาวรที่มีไฟล์เป็นการเริ่มต้นที่ดี นี่เป็นตัวแทนที่ชัดเจน (เห็นได้ชัดเนื่องจากคุณสามารถกู้คืนไฟล์ได้โดยการแยกไฟล์เก็บถาวร) มันอาจรวมถึงข้อมูลเมตาของไฟล์เช่นวันที่และความเป็นเจ้าของ อย่างไรก็ตามสิ่งนี้ยังไม่ถูกต้อง: การเก็บถาวรนั้นไม่ชัดเจนเนื่องจากการแสดงนั้นขึ้นอยู่กับลำดับการจัดเก็บไฟล์และถ้ามีการบีบอัด
ทางออกคือการเรียงลำดับชื่อไฟล์ก่อนเก็บถาวร หากชื่อไฟล์ของคุณไม่มีบรรทัดใหม่คุณสามารถเรียกใช้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)
LC_ALL=C
เป็นสิ่งสำคัญหากใช้กับเครื่องและระบบปฏิบัติการหลายเครื่อง
cpio -o -
หมายความว่าอย่างไร cpio ใช้ stdin / out เป็นค่าเริ่มต้นหรือไม่? GNU cpio 2.12 ผลิตcpio: Too many arguments
มีลักษณะที่md5deep คุณสมบัติบางอย่างของ md5deep ที่คุณอาจสนใจ:
การดำเนินการซ้ำ - md5deep สามารถตรวจสอบทรีไดเรกทอรีทั้งหมด นั่นคือคำนวณ MD5 สำหรับทุกไฟล์ในไดเรกทอรีและสำหรับทุกไฟล์ในทุกไดเรกทอรีย่อย
โหมดเปรียบเทียบ - md5deep สามารถยอมรับรายการของแฮชที่รู้จักและเปรียบเทียบกับชุดของไฟล์อินพุต โปรแกรมสามารถแสดงไฟล์อินพุตเหล่านั้นที่ตรงกับรายการของแฮชที่รู้จักหรือไฟล์ที่ไม่ตรงกัน
...
.../foo: Is a directory
อะไรให้
md5deep -r -l -j0 . | md5sum
(โดยที่-r
เรียกซ้ำ-l
หมายถึง "ใช้พา ธ สัมพัทธ์" เพื่อให้พา ธ สัมบูรณ์ของไฟล์ไม่รบกวนเมื่อพยายามเปรียบเทียบเนื้อหาของสองไดเรกทอรีและ-j0
ใช้ 1 เธรดเพื่อป้องกันการไม่กำหนด ไปที่ md5sums แต่ละรายการจะถูกส่งคืนในคำสั่งซื้อที่ต่างกัน)
หากเป้าหมายของคุณเพียงเพื่อค้นหาความแตกต่างระหว่างสองไดเรกทอรีให้ลองใช้ diff
ลองสิ่งนี้:
diff -qr dir1 dir2
คุณสามารถแฮชไฟล์ทุกไฟล์ซ้ำแล้วทำการแฮชข้อความผลลัพธ์:
> md5deep -r -l . | sort | md5sum
d43417958e47758c6405b5098f151074 *-
ต้องมีmd5deep
md5deep
ใช้hashdeep
บน Ubuntu 16.04 เพราะแพ็คเกจ md5deep เป็นเพียงหุ่นจำลองสำหรับ hashdeep
## Invoked from: /home/myuser/dev/
## $ hashdeep -s -r -l ~/folder/
สิ่งนี้จะต้องเรียงลำดับดังนั้นแฮชสุดท้ายจะแตกต่างกันหากคุณเปลี่ยนโฟลเดอร์ปัจจุบันหรือบรรทัดคำสั่ง
ฉันต้องการเวอร์ชันที่ตรวจสอบชื่อไฟล์เพียงเพราะเนื้อหาอยู่ในไดเรกทอรีที่ต่างกัน
รุ่นนี้ (คำตอบของ Warren Young)ช่วยได้มาก แต่รุ่นของฉันmd5sum
ส่งออกชื่อไฟล์ (สัมพันธ์กับเส้นทางที่ฉันเรียกใช้คำสั่งจาก) และชื่อโฟลเดอร์แตกต่างกันดังนั้นแม้ว่าการตรวจสอบไฟล์แต่ละไฟล์จะตรงกับการตรวจสอบขั้นสุดท้าย 'T
ในการแก้ไขนั้นในกรณีของฉันฉันแค่ต้องตัดชื่อไฟล์ออกจากแต่ละบรรทัดของfind
เอาต์พุต (เลือกเฉพาะคำแรกที่คั่นด้วยช่องว่างโดยใช้cut
):
find -s somedir -type f -exec md5sum {} \; | cut -d" " -f1 | md5sum
วิธีแก้ปัญหา :
$ pip install checksumdir
$ checksumdir -a md5 assets/js
981ac0bc890de594a9f2f40e00f13872
$ checksumdir -a sha1 assets/js
88cd20f115e31a1e1ae381f7291d0c8cd3b92fad
ใช้งานได้ง่ายและรวดเร็วขึ้นวิธีการแก้ปัญหาแล้วทุบตีสคริปต์
nix-hash
จากผู้จัดการแพคเกจระวัง
คำสั่ง nix-hash คำนวณแฮชการเข้ารหัสของเนื้อหาของแต่ละพา ธ และพิมพ์ลงบนเอาต์พุตมาตรฐาน โดยค่าเริ่มต้นมันคำนวณ MD5 แฮช แต่อัลกอริทึมแฮชอื่น ๆ ที่มีอยู่เช่นกัน แฮชจะพิมพ์เป็นเลขฐานสิบหก
แฮชถูกคำนวณบนการทำให้เป็นอนุกรมของแต่ละพา ธ : ดัมพ์ของทรีของระบบไฟล์ที่รูทที่พา ธ สิ่งนี้อนุญาตให้ไดเรกทอรีและ symlink ถูกแฮชรวมถึงไฟล์ปกติ ดัมพ์อยู่ในรูปแบบ NAR ที่สร้างโดย nix-store --dump ดังนั้นเส้นทาง nix-hash ให้ผลตอบแทนแฮชการเข้ารหัสเช่นเดียวกับ nix-store --dump path | md5sum
ฉันใช้ส่วนย่อยนี้สำหรับปริมาณปานกลาง :
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
ธงทำอย่างไร
man find
และอ่านคู่มือที่ดี;)
-xdev Don't descend directories on other filesystems.
การตรวจสอบต้นไม้ที่ดีคือ tree-id ของ Git
ขออภัยไม่มีเครื่องมือแบบสแตนด์อโลนที่สามารถทำได้ (อย่างน้อยฉันก็ไม่รู้) แต่ถ้าคุณมี Git คุณสามารถแกล้งตั้งค่าพื้นที่เก็บข้อมูลใหม่และเพิ่มไฟล์ที่คุณต้องการตรวจสอบไปยังดัชนี
สิ่งนี้ช่วยให้คุณสามารถสร้างแฮชทรี (ที่ทำซ้ำได้) ซึ่งมีเฉพาะเนื้อหาชื่อไฟล์และโหมดไฟล์ที่ลดขนาด (ปฏิบัติการ)
จากการติดตามคำตอบที่ยอดเยี่ยมนี้หากคุณพบว่าตัวเองต้องการเร่งการคำนวณผลรวมตรวจสอบสำหรับไดเรกทอรีขนาดใหญ่ให้ลองใช้GNU Parallel :
find -s somedir -type f | parallel -k -n 100 md5 {} | md5
(นี่คือการใช้ Mac ด้วยmd5
แทนที่ตามที่จำเป็น)
การ-k
ตั้งค่าสถานะเป็นสิ่งสำคัญที่แนะนำparallel
ให้รักษาลำดับมิฉะนั้นผลรวมโดยรวมสามารถเปลี่ยนเรียกใช้เพื่อเรียกใช้แม้ว่าไฟล์จะเหมือนกันทั้งหมด -n 100
บอกให้รันแต่ละอินสแตนซ์ที่md5
มีอาร์กิวเมนต์ 100 ตัวนี่เป็นพารามิเตอร์ที่คุณสามารถปรับแต่งเพื่อให้ได้เวลาการทำงานที่ดีที่สุด ดูการ-X
ตั้งค่าสถานะของparallel
(แม้ว่าในกรณีส่วนบุคคลของฉันที่ทำให้เกิดข้อผิดพลาด)
สคริปต์ที่มีการทดสอบอย่างดีและสนับสนุนจำนวนของการดำเนินงานรวมทั้งการหาที่ซ้ำกันทำรถทั้งข้อมูลและเมตาดาต้าแสดงเพิ่มเติมรวมทั้งการเปลี่ยนแปลงและการลบที่คุณอาจชอบลายนิ้วมือ
ลายนิ้วมือในขณะนี้ไม่ได้สร้าง checksum เดียวสำหรับไดเรกทอรี แต่ไฟล์ transcript ซึ่งรวมถึง checksums สำหรับไฟล์ทั้งหมดในไดเรกทอรีนั้น
fingerprint analyze
สิ่งนี้จะสร้างindex.fingerprint
ในไดเรกทอรีปัจจุบันซึ่งรวมถึง checksums ชื่อไฟล์และขนาดไฟล์ โดยค่าเริ่มต้นจะใช้ทั้งสองและMD5
SHA1.256
ในอนาคตฉันหวังว่าจะเพิ่มการสนับสนุนสำหรับต้นไม้ Merkle ลงในลายนิ้วมือซึ่งจะให้การตรวจสอบระดับบนสุดเพียงครั้งเดียว ตอนนี้คุณต้องเก็บไฟล์นั้นไว้เพื่อทำการตรวจสอบ
ฉันไม่ต้องการโปรแกรมปฏิบัติการใหม่หรือโซลูชันที่ไม่น่าสนใจดังนั้นนี่คือสิ่งที่ฉันต้องทำ:
#!/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
นี่คือสิ่งที่ฉันมีอยู่ด้านบนหัวของฉันคนใดคนหนึ่งที่ใช้เวลาในการทำงานเกี่ยวกับเรื่องนี้จริง ๆ จะได้รับกรณี 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
ทำทีละไฟล์สำหรับแต่ละไดเรกทอรี
# 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'
คำตอบนี้มีจุดประสงค์เพื่อเป็นการปรับปรุงเพิ่มเติมสำหรับวิธีการใช้ 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
ที่จริงผมใช้
หากคุณไม่ต้องการ md5 คุณสามารถลอง
find . -type f | xargs cksum | cksum
find .
find somedir
วิธีนี้ชื่อไฟล์จะเหมือนกันเมื่อมีการระบุรายละเอียดพา ธ ที่แตกต่างกัน นี้สามารถหากิน :-)