ฉันจะคำนวณการตรวจสอบ md5 ของไดเร็กทอรีได้อย่างไร


136

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

วิธีที่ดีที่สุดคืออะไร?

แก้ไข:โซลูชันที่นำเสนอนั้นดีมาก แต่นี่ไม่ใช่สิ่งที่ฉันต้องการ ฉันกำลังมองหาวิธีแก้ปัญหาเพื่อรับการตรวจสอบสรุปเดียวซึ่งจะระบุไดเร็กทอรีโดยรวมโดยไม่ซ้ำกัน - รวมถึงเนื้อหาของไดเรกทอรีย่อยทั้งหมด


ลองดูที่นี้และนี้สำหรับคำอธิบายรายละเอียดเพิ่มเติม
luvieere

3
ดูเหมือนจะเป็นคำถาม superuser สำหรับฉัน
Noldorin

9
โปรดทราบว่าเช็คซัมไม่ได้ระบุสิ่งใดโดยเฉพาะ
Hosam Aly

1
เหตุใดคุณจึงมีแผนผังไดเร็กทอรีสองรายการที่อาจ "เหมือนกัน" ที่คุณต้องการระบุโดยไม่ซ้ำกัน เวลาในการสร้าง / แก้ไข / เข้าถึงไฟล์มีความสำคัญหรือไม่ เวอร์ชันควบคุมสิ่งที่คุณต้องการจริงๆหรือไม่?
jmucchiello

สิ่งที่สำคัญจริงๆในกรณีของฉันคือความคล้ายคลึงกันของเนื้อหาแผนผังไดเรกทอรีทั้งหมดซึ่งหมายถึง AFAIK สิ่งต่อไปนี้: 1) เนื้อหาของไฟล์ใด ๆ ภายใต้แผนผังไดเรกทอรีไม่ได้รับการเปลี่ยนแปลง 2) ไม่มีการเพิ่มไฟล์ใหม่ในแผนผังไดเรกทอรี 3) ไม่มีไฟล์ ถูกลบ
victorz

คำตอบ:


154
find /path/to/dir/ -type f -name "*.py" -exec md5sum {} + | awk '{print $1}' | sort | md5sum

คำสั่ง find แสดงรายการไฟล์ทั้งหมดที่ลงท้ายด้วย. py md5sum ถูกคำนวณสำหรับไฟล์. py แต่ละไฟล์ awk ใช้เพื่อเลือก md5sums (ละเว้นชื่อไฟล์ซึ่งอาจไม่ซ้ำกัน) md5sums ถูกจัดเรียง md5sum ของรายการที่เรียงลำดับนี้จะถูกส่งกลับ

ฉันได้ทดสอบโดยการคัดลอกไดเร็กทอรีทดสอบ:

rsync -a ~/pybin/ ~/pybin2/

ฉันเปลี่ยนชื่อไฟล์บางไฟล์ใน ~ / pybin2

find...md5sumคำสั่งส่งคืนการส่งออกเหมือนกันสำหรับทั้งไดเรกทอรี

2bcf49a4d19ef9abd284311108d626f1  -

24
โปรดทราบว่าการตรวจสอบจะถูกสร้างขึ้นหากไฟล์ถูกเปลี่ยนชื่อ ดังนั้นนี่จึงไม่เหมาะกับ "checksum ซึ่งจะระบุไดเร็กทอรีโดยรวมโดยเฉพาะ" หากคุณพิจารณาว่าเป็นส่วนการจัดวางไฟล์ของลายเซ็น
Valentin Milea

1
คุณสามารถเปลี่ยนบรรทัดคำสั่งเล็กน้อยเพื่อนำหน้าแต่ละไฟล์ checksum ด้วยชื่อของไฟล์ (หรือดีกว่านั้นคือพา ธ สัมพัทธ์ของไฟล์จาก / path / to / dir /) ดังนั้นจึงถูกนำมาพิจารณาในการตรวจสอบขั้นสุดท้าย
Michael Zilbermann

4
@ zim2001: ใช่มันสามารถเปลี่ยนแปลงได้ แต่เมื่อฉันเข้าใจปัญหา (โดยเฉพาะอย่างยิ่งเนื่องจากความคิดเห็นของ OP ภายใต้คำถาม) OP ต้องการให้สองไดเร็กทอรีใด ๆ ได้รับการพิจารณาว่าเท่าเทียมกันหากเนื้อหาของไฟล์เหมือนกันโดยไม่คำนึงถึงชื่อไฟล์หรือ แม้แต่เส้นทางสัมพัทธ์
unutbu

@unutbu: ฉันรู้; ฉันกำลังตอบสนองต่อบันทึกก่อนหน้าจากวาเลนตินมิเลีย
Michael Zilbermann

@ValentinMilea เพียงแค่ลบawk ...ส่วนถ้าคุณพิจารณาเค้าโครงส่วนของลายเซ็น
segfault

167

สร้างไฟล์เก็บถาวร tar ได้ทันทีและไปยังmd5sum:

tar c dir | md5sum

สิ่งนี้จะสร้าง md5sum เดียวที่ควรไม่ซ้ำกันสำหรับไฟล์และการตั้งค่าไดเร็กทอรีย่อยของคุณ ไม่มีการสร้างไฟล์บนดิสก์


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

18
ls -alR dir | md5sum. นี่จะดีกว่าไม่มีการบีบอัดเพียงแค่อ่าน มันไม่เหมือนใครเพราะเนื้อหามีเวลา mod และขนาดของไฟล์;)
Sid

14
@ Daps0l - ไม่มีการบีบอัดในคำสั่งของฉัน คุณต้องเพิ่มzสำหรับ gzip หรือjสำหรับ bzip2 ฉันไม่ได้ทำทั้งสองอย่าง
ire_and_curses

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

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

47

คำแนะนำในการใช้ ire_and_curses tar c <dir>มีปัญหาบางประการ:

  • tar ประมวลผลรายการไดเร็กทอรีตามลำดับที่เก็บไว้ในระบบไฟล์และไม่มีวิธีใดที่จะเปลี่ยนลำดับนี้ สิ่งนี้สามารถให้ผลลัพธ์ที่แตกต่างไปจากเดิมอย่างสิ้นเชิงหากคุณมีไดเร็กทอรี "เดียวกัน" ในที่ต่างๆและฉันรู้วิธีแก้ไขปัญหานี้ไม่ได้ (tar ไม่สามารถ "เรียงลำดับ" ไฟล์อินพุตตามลำดับที่เจาะจงได้)
  • ฉันมักจะสนใจว่าหมายเลข groupid และ ownerid เหมือนกันหรือไม่ไม่จำเป็นว่าการแสดงสตริงของกลุ่ม / เจ้าของจะเหมือนกัน สิ่งนี้สอดคล้องกับสิ่งที่ทำตัวอย่างเช่นrsync -a --deleteมันซิงโครไนซ์แทบทุกอย่าง (ลบ xattrs และ acls) แต่จะซิงค์เจ้าของและกลุ่มตาม ID ไม่ใช่การแสดงสตริง ดังนั้นหากคุณซิงค์กับระบบอื่นที่ไม่จำเป็นต้องมีผู้ใช้ / กลุ่มเดียวกันคุณควรเพิ่ม--numeric-ownerแฟล็กลงใน tar
  • tar จะรวมชื่อไฟล์ของไดเร็กทอรีที่คุณกำลังตรวจสอบตัวเองเป็นเพียงสิ่งที่ควรระวัง

ตราบเท่าที่ไม่มีการแก้ไขสำหรับปัญหาแรก (หรือเว้นแต่คุณแน่ใจว่าไม่มีผลกับคุณ) ฉันจะไม่ใช้วิธีนี้

findการแก้ปัญหาตามที่เสนอข้างต้นนี้ยังไม่ดีเพราะพวกเขารวมถึงแฟ้มไม่ไดเรกทอรีซึ่งกลายเป็นปัญหาถ้าคุณ Checksumming ควรเก็บไว้ในใจไดเรกทอรีว่าง

สุดท้ายโซลูชันที่แนะนำส่วนใหญ่จะไม่เรียงลำดับอย่างสม่ำเสมอเนื่องจากการเปรียบเทียบอาจแตกต่างกันในระบบต่างๆ

นี่คือวิธีแก้ปัญหาที่ฉันคิดขึ้น:

dir=<mydir>; (find "$dir" -type f -exec md5sum {} +; find "$dir" -type d) | LC_ALL=C sort | md5sum

หมายเหตุเกี่ยวกับโซลูชันนี้:

  • LC_ALL=Cคือเพื่อให้แน่ใจเพื่อเรียงลำดับความน่าเชื่อถือในระบบ
  • สิ่งนี้ไม่ได้แยกความแตกต่างระหว่างไดเร็กทอรี "named \ nwithanewline" และ 2 ไดเร็กทอรี "named" และ "withanewline" แต่โอกาสที่จะเกิดขึ้นดูเหมือนไม่น่าเป็นไปได้มาก หนึ่งมักจะแก้ไขปัญหานี้ด้วย-print0แฟล็กfindแต่เนื่องจากมีสิ่งอื่นเกิดขึ้นที่นี่ฉันจึงเห็นโซลูชันที่จะทำให้คำสั่งซับซ้อนมากขึ้นเท่านั้นจึงคุ้มค่า

PS: หนึ่งในระบบของฉันใช้ busybox แบบ จำกัดfindซึ่งไม่รองรับ-execหรือ-print0แฟล็กและยังต่อท้าย '/' เพื่อแสดงถึงไดเร็กทอรีในขณะที่ดูเหมือนว่า findutils ไม่พบดังนั้นสำหรับเครื่องนี้ฉันต้องเรียกใช้:

dir=<mydir>; (find "$dir" -type f | while read f; do md5sum "$f"; done; find "$dir" -type d | sed 's#/$##') | LC_ALL=C sort | md5sum

โชคดีที่ฉันไม่มีไฟล์ / ไดเรกทอรีที่มีบรรทัดใหม่ในชื่อดังนั้นนี่ไม่ใช่ปัญหาในระบบนั้น


1
+1: น่าสนใจมาก! คุณกำลังบอกว่าลำดับอาจแตกต่างกันระหว่างประเภทระบบไฟล์ที่แตกต่างกันหรืออยู่ในระบบไฟล์เดียวกัน?
ire_and_curses

2
ทั้งสองอย่าง ขึ้นอยู่กับลำดับของรายการไดเร็กทอรีภายในแต่ละไดเร็กทอรี รายการไดเร็กทอรี AFAIK (ในระบบไฟล์) ถูกสร้างขึ้นตามลำดับที่คุณ "สร้างไฟล์ในไดเร็กทอรี" ตัวอย่างง่ายๆ: $ mkdir a; สัมผัส a / file-1; แตะ a / file-2 $ mkdir b; สัมผัส b / file-2; สัมผัส b / file-1 $ (cd a; tar -c. | md5sum) fb29e7af140aeea5a2647974f7cdec77 - $ (cd b; tar -c. | md5sum) a3a39358158a87059b9f111ccffa1023 -
Dieter_be

15

หากคุณสนใจเฉพาะไฟล์ไม่ใช่ไดเร็กทอรีว่างสิ่งนี้ใช้ได้ดี:

find /path -type f | sort -u | xargs cat | md5sum

10

เพื่อความสมบูรณ์มีmd5deep (1) ; ไม่สามารถใช้ได้โดยตรงเนื่องจากข้อกำหนด * .py filter แต่ควรดำเนินการร่วมกับ find (1)


ฉันจะใช้พารามิเตอร์ใดหากต้องการคำนวณการตรวจสอบ md5 ของไดเร็กทอรีเท่านั้น
Gabriel Fair

9

วิธีแก้ปัญหาที่ได้ผลดีที่สุดสำหรับฉัน:

find "$path" -type f -print0 | sort -z | xargs -r0 md5sum | md5sum

เหตุผลว่าทำไมมันถึงได้ผลดีที่สุดสำหรับฉัน:

  1. จัดการชื่อไฟล์ที่มีช่องว่าง
  2. ละเว้นข้อมูลเมตาของระบบไฟล์
  3. ตรวจจับว่าไฟล์ถูกเปลี่ยนชื่อหรือไม่

ปัญหาเกี่ยวกับคำตอบอื่น ๆ :

ระบบไฟล์ข้อมูลเมตาไม่ถูกละเว้นสำหรับ:

tar c - "$path" | md5sum

ไม่จัดการชื่อไฟล์ที่มีช่องว่างและตรวจพบว่าไฟล์ถูกเปลี่ยนชื่อ:

find /path -type f | sort -u | xargs cat | md5sum

4

ถ้าคุณต้องการหนึ่ง md5sum ที่ครอบคลุมทั้งไดเร็กทอรีฉันจะทำสิ่งที่ชอบ

cat *.py | md5sum 

1
สำหรับ subdirs ใช้สิ่งที่ต้องการcat **.py| md5sum
Ramon

3

ตรวจสอบไฟล์ทั้งหมดรวมทั้งเนื้อหาและชื่อไฟล์

grep -ar -e . /your/dir | md5sum | cut -c-32

เหมือนกับข้างบน แต่รวมเฉพาะไฟล์ * .py

grep -ar -e . --include="*.py" /your/dir | md5sum | cut -c-32

คุณยังสามารถติดตาม symlink ได้หากต้องการ

grep -aR -e . /your/dir | md5sum | cut -c-32

ตัวเลือกอื่น ๆ ที่คุณสามารถพิจารณาใช้กับ grep

-s, --no-messages         suppress error messages
-D, --devices=ACTION      how to handle devices, FIFOs and sockets;
-Z, --null                print 0 byte after FILE name
-U, --binary              do not strip CR characters at EOL (MSDOS/Windows)


2

ในทางเทคนิคคุณต้องวิ่งls -lR *.py | md5sumเท่านั้น หากคุณไม่กังวลว่าจะมีใครแก้ไขไฟล์และแตะกลับไปยังวันที่เดิมและไม่เคยเปลี่ยนขนาดไฟล์ผลลัพธ์จากlsควรจะบอกคุณว่าไฟล์มีการเปลี่ยนแปลงหรือไม่ unix-foo ของฉันอ่อนแอดังนั้นคุณอาจต้องการพารามิเตอร์บรรทัดคำสั่งเพิ่มเติมเพื่อให้ได้เวลาในการสร้างและเวลาแก้ไขในการพิมพ์ lsจะบอกคุณด้วยว่าสิทธิ์ในไฟล์มีการเปลี่ยนแปลงหรือไม่ (และฉันแน่ใจว่ามีสวิตช์ที่จะปิดหากคุณไม่สนใจ)


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


1

ฉันมีปัญหาเดียวกันดังนั้นฉันจึงสร้างสคริปต์นี้ขึ้นมาซึ่งแสดงรายการ md5sums ของไฟล์ในไดเร็กทอรีและหากพบไดเร็กทอรีย่อยมันจะทำงานอีกครั้งจากที่นั่นเพื่อให้สิ่งนี้เกิดขึ้นสคริปต์จะต้องสามารถทำงานผ่านปัจจุบันได้ ไดเร็กทอรีหรือจากไดเร็กทอรีย่อยหากอาร์กิวเมนต์ดังกล่าวถูกส่งใน $ 1

#!/bin/bash

if [ -z "$1" ] ; then

# loop in current dir
ls | while read line; do
  ecriv=`pwd`"/"$line
if [ -f $ecriv ] ; then
    md5sum "$ecriv"
elif [ -d $ecriv ] ; then
    sh myScript "$line" # call this script again
fi

done


else # if a directory is specified in argument $1

ls "$1" | while read line; do
  ecriv=`pwd`"/$1/"$line

if [ -f $ecriv ] ; then
    md5sum "$ecriv"

elif [ -d $ecriv ] ; then
    sh myScript "$line"
fi

done


fi

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

1

หากคุณต้องการความเป็นอิสระจากแอตทริบิวต์ระบบไฟล์และจากความแตกต่างระดับบิตของ tar บางเวอร์ชันคุณสามารถใช้ cpio:

cpio -i -e theDirname | md5sum

0

มีอีกสองวิธีแก้ไข:

สร้าง:

du -csxb /path | md5sum > file

ls -alR -I dev -I run -I sys -I tmp -I proc /path | md5sum > /tmp/file

ตรวจสอบ:

du -csxb /path | md5sum -c file

ls -alR -I dev -I run -I sys -I tmp -I proc /path | md5sum -c /tmp/file

0

md5sumทำงานได้ดีสำหรับฉัน แต่ฉันมีปัญหาเกี่ยวกับsortและการเรียงลำดับชื่อไฟล์ ดังนั้นฉันจึงจัดเรียงตามmd5sumผลลัพธ์แทน ฉันยังต้องยกเว้นบางไฟล์เพื่อสร้างผลลัพธ์ที่เทียบเคียงได้

find . -type f -print0 \ | xargs -r0 md5sum \ | grep -v ".env" \ | grep -v "vendor/autoload.php" \ | grep -v "vendor/composer/" \ | sort -d \ | md5sum


0

ฉันต้องการเพิ่มว่าหากคุณพยายามทำสิ่งนี้สำหรับไฟล์ / ไดเร็กทอรีในที่เก็บ git เพื่อติดตามว่ามีการเปลี่ยนแปลงหรือไม่นี่เป็นแนวทางที่ดีที่สุด:

git log -1 --format=format:%H --full-diff <file_or_dir_name>

และถ้าไม่ใช่ git-directory / repo ให้ตอบโดย @ire_and_curses น่าจะเป็นทางออกที่ดีที่สุด:

tar c <dir_name> | md5sum

อย่างไรก็ตามโปรดทราบว่าtarคำสั่งจะเปลี่ยนแฮชเอาต์พุตหากคุณเรียกใช้ในระบบปฏิบัติการและอื่น ๆ หากคุณต้องการมีภูมิคุ้มกันนี่เป็นแนวทางที่ดีที่สุดแม้ว่าจะดูไม่สวยหรูตั้งแต่แรกเห็นก็ตาม:

find <dir_name> -type f -print0 | sort -z | xargs -0 md5sum | md5sum | awk '{ print $1 }'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.