Làm thế nào tôi có thể tính toán tổng kiểm tra md5 của một thư mục?


133

Tôi cần tính toán tổng kiểm tra md5 cho tất cả các tệp thuộc một loại cụ thể ( *.pyví dụ) được đặt trong một thư mục và tất cả các thư mục con.

Cách tốt nhất để làm điều đó là gì?

Chỉnh sửa: Các giải pháp được đề xuất là rất tốt, nhưng đây không phải là chính xác những gì tôi cần. Tôi đang tìm kiếm một giải pháp để có được một tổng kiểm tra tóm tắt duy nhất sẽ xác định duy nhất toàn bộ thư mục - bao gồm nội dung của tất cả các thư mục con của nó.


Hãy xem cái nàycái này để được giải thích chi tiết hơn.
luvieere

3
Có vẻ như một câu hỏi siêu người đối với tôi.
Noldorin

8
Lưu ý rằng tổng kiểm tra không xác định duy nhất bất cứ điều gì.
Hosam Aly

1
Tại sao bạn có hai cây thư mục có thể hoặc không thể "giống nhau" mà bạn muốn xác định duy nhất? Liệu tập tin tạo / sửa đổi / thời gian truy cập có vấn đề? Là phiên bản kiểm soát những gì bạn thực sự cần?
jmucchiello

Điều thực sự quan trọng trong trường hợp của tôi là sự giống nhau của toàn bộ nội dung cây thư mục, có nghĩa là AFAIK như sau: 1) nội dung của bất kỳ tệp nào trong cây thư mục không bị thay đổi 2) không có tệp mới nào được thêm vào cây thư mục 3) không có tệp đã bị xóa
victorz

Câu trả lời:


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

Lệnh find liệt kê tất cả các tệp kết thúc bằng .py. Md5sum được tính cho mỗi tệp .py. awk được sử dụng để chọn ra md5sums (bỏ qua tên tệp, có thể không phải là duy nhất). Các md5sums được sắp xếp. Md5sum của danh sách được sắp xếp này sau đó được trả về.

Tôi đã kiểm tra điều này bằng cách sao chép một thư mục kiểm tra:

rsync -a ~/pybin/ ~/pybin2/

Tôi đã đổi tên một số tệp trong ~ / pybin2.

Các find...md5sumlệnh trả về kết quả tương tự cho cả hai thư mục.

2bcf49a4d19ef9abd284311108d626f1  -

24
Lưu ý rằng cùng một tổng kiểm tra sẽ được tạo nếu một tệp được đổi tên. Vì vậy, điều này không thực sự phù hợp với "tổng kiểm tra sẽ xác định duy nhất toàn bộ thư mục" nếu bạn xem xét phần bố cục tệp của chữ ký.
Valentin Milea

1
bạn có thể thay đổi một chút dòng lệnh thành tiền tố mỗi tổng kiểm tra tệp với tên của tệp (hoặc thậm chí tốt hơn, đường dẫn tương đối của tệp từ / path / đến / dir /) để nó được tính đến trong tổng kiểm tra cuối cùng.
Michael Zilbermann

4
@ zim2001: Có, nó có thể bị thay đổi, nhưng khi tôi hiểu vấn đề (đặc biệt là do nhận xét của OP theo câu hỏi), OP muốn bất kỳ hai thư mục nào được coi là bằng nhau nếu nội dung của các tệp giống nhau bất kể tên tệp hay thậm chí đường dẫn tương đối.
unutbu

@unutbu: Tôi biết; tôi đã phản ứng với ghi chú trước đó, từ Valentin Milea.
Michael Zilbermann

@ValentinMilea chỉ cần loại bỏ awk ...phần nếu bạn xem xét phần bố trí của chữ ký.
segfault

166

Tạo một tệp lưu trữ tar khi đang bay và ống dẫn đến md5sum:

tar c dir | md5sum

Điều này tạo ra một md5sum duy nhất phải là duy nhất cho thiết lập thư mục và thư mục con của bạn. Không có tập tin được tạo trên đĩa.


25
@CharlesB với một tổng kiểm tra duy nhất bạn không bao giờ biết tệp nào khác. Câu hỏi là về một tổng kiểm tra duy nhất cho một thư mục.
Hawken

17
ls -alR dir | md5sum. Điều này thậm chí còn tốt hơn không nén chỉ là một đọc. Nó là duy nhất vì nội dung chứa thời gian mod và kích thước của tệp;)
Sid

14
@ Daps0l - không có nén trong lệnh của tôi. Bạn cần thêm zcho gzip, hoặc jcho bzip2. Tôi cũng không làm.
ire_and_curses

7
Hãy cẩn thận rằng việc này sẽ tích hợp dấu thời gian của các tệp và các nội dung khác trong tính toán tổng kiểm tra, không chỉ nội dung của các tệp
Michael Zilbermann

10
Điều này thật dễ thương, nhưng nó không thực sự hiệu quả. Không có gì đảm bảo rằng tarviệc nhập cùng một tập tin hai lần hoặc trên hai máy tính khác nhau sẽ mang lại kết quả chính xác như nhau.
fletom

46

Đề xuất sử dụng của ire_and_curses tar c <dir>có một số vấn đề:

  • tar xử lý các mục trong thư mục theo thứ tự chúng được lưu trữ trong hệ thống tập tin và không có cách nào để thay đổi thứ tự này. Điều này thực sự có thể mang lại kết quả hoàn toàn khác nhau nếu bạn có thư mục "giống nhau" ở những nơi khác nhau và tôi biết không có cách nào để khắc phục điều này (tar không thể "sắp xếp" các tệp đầu vào của nó theo một thứ tự cụ thể).
  • Tôi thường quan tâm đến việc liệu số nhóm và chủ sở hữu có giống nhau hay không, không nhất thiết là liệu đại diện chuỗi của nhóm / chủ sở hữu có giống nhau hay không. Điều này phù hợp với những gì ví dụ rsync -a --delete: nó đồng bộ hóa hầu như mọi thứ (trừ xattrs và acls), nhưng nó sẽ đồng bộ hóa chủ sở hữu và nhóm dựa trên ID của họ, chứ không phải trên biểu diễn chuỗi. Vì vậy, nếu bạn đã đồng bộ hóa với một hệ thống khác không nhất thiết phải có cùng người dùng / nhóm, bạn nên thêm --numeric-ownercờ vào tar
  • tar sẽ bao gồm tên tệp của thư mục bạn đang kiểm tra chính nó, chỉ cần một cái gì đó để nhận biết.

Miễn là không có cách khắc phục cho sự cố đầu tiên (hoặc trừ khi bạn chắc chắn rằng nó không ảnh hưởng đến bạn), tôi sẽ không sử dụng phương pháp này.

Các findgiải pháp dựa trên đề xuất ở trên cũng không tốt vì chúng chỉ bao gồm các tệp, không bao gồm các thư mục, sẽ trở thành một vấn đề nếu bạn kiểm tra nên ghi nhớ các thư mục trống.

Cuối cùng, hầu hết các giải pháp được đề xuất không sắp xếp nhất quán, vì đối chiếu có thể khác nhau giữa các hệ thống.

Đây là giải pháp tôi đã đưa ra:

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

Lưu ý về giải pháp này:

  • Để LC_ALL=Cđảm bảo thứ tự sắp xếp đáng tin cậy trên các hệ thống
  • Điều này không phân biệt giữa một thư mục "có tên \ nwithanewline" và hai thư mục "có tên" và "withanewline", nhưng khả năng xảy ra điều đó dường như rất khó xảy ra. Người ta thường sửa lỗi này bằng -print0cờ findnhưng vì có những thứ khác đang diễn ra ở đây, tôi chỉ có thể thấy các giải pháp làm cho lệnh trở nên phức tạp hơn nên nó có giá trị.

PS: một trong những hệ thống của tôi sử dụng một busybox hạn chế findmà không hỗ trợ -execlẫn -print0cờ, và cũng có thể nó gắn thêm '/' để biểu thị các thư mục, trong khi findutils tìm dường như không, vì vậy cho máy này, tôi cần phải chạy:

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

May mắn thay, tôi không có tệp / thư mục có dòng mới trong tên của họ, vì vậy đây không phải là vấn đề trên hệ thống đó.


1
+1: Rất thú vị! Bạn đang nói rằng thứ tự có thể khác nhau giữa các loại hệ thống tập tin khác nhau, hoặc trong cùng một hệ thống tập tin?
ire_and_curses

2
cả hai. nó chỉ phụ thuộc vào thứ tự của các mục trong thư mục. Các mục nhập thư mục AFAIK (trong hệ thống tệp) chỉ được tạo theo thứ tự mà bạn "tạo tệp trong thư mục". Một ví dụ đơn giản: $ mkdir a; chạm vào a / file-1; chạm vào a / file-2 $ mkdir b; chạm b / file-2; touch b / file-1 $ (cd a; tar -c | md5sum.) fb29e7af140aeea5a2647974f7cdec77 - $ (cd b;. tar -c | md5sum) a3a39358158a87059b9f111ccffa1023 -
Dieter_be

14

Nếu bạn chỉ quan tâm đến các tập tin và không phải các thư mục trống, điều này hoạt động độc đáo:

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

10

Để hoàn thiện, có md5deep (1) ; nó không thể áp dụng trực tiếp do yêu cầu bộ lọc * .py nhưng sẽ hoạt động tốt cùng với find (1).


Tôi sẽ sử dụng tham số nào nếu tôi chỉ muốn tính toán tổng kiểm tra md5 của một thư mục?
Hội chợ Gabriel

9

Một giải pháp hiệu quả nhất với tôi:

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

Lý do tại sao nó làm việc tốt nhất cho tôi:

  1. xử lý tên tệp chứa khoảng trắng
  2. Bỏ qua siêu dữ liệu hệ thống tập tin
  3. Phát hiện nếu tập tin đã được đổi tên

Các vấn đề với câu trả lời khác:

Dữ liệu meta hệ thống tập tin không được bỏ qua cho:

tar c - "$path" | md5sum

Không xử lý tên tệp chứa khoảng trắng cũng như không phát hiện nếu tệp đã được đổi tên:

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

4

Nếu bạn muốn một md5sum bao trùm toàn bộ thư mục, tôi sẽ làm một cái gì đó như

cat *.py | md5sum 

1
Đối với các thư mục con sử dụng một cái gì đó như cat **.py| md5sum
Ramon

3

Kiểm tra tất cả các tệp, bao gồm cả nội dung và tên tệp của chúng

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

Tương tự như trên, nhưng chỉ bao gồm các tệp * .py

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

Bạn cũng có thể theo liên kết tượng trưng nếu bạn muốn

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

Các tùy chọn khác bạn có thể cân nhắc sử dụng với 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

Về mặt kỹ thuật bạn chỉ cần chạy ls -lR *.py | md5sum. Trừ khi bạn lo lắng về việc ai đó sửa đổi các tệp và đưa chúng trở lại ngày ban đầu của chúng và không bao giờ thay đổi kích thước của tệp, đầu ra từ lssẽ cho bạn biết nếu tệp đã thay đổi. Unix-foo của tôi yếu nên bạn có thể cần thêm một số tham số dòng lệnh để lấy thời gian tạo và thời gian sửa đổi để in. lscũng sẽ cho bạn biết nếu quyền trên các tệp đã thay đổi (và tôi chắc chắn có các công tắc để tắt nếu bạn không quan tâm đến điều đó).


3
Điều này có thể phù hợp với một số trường hợp sử dụng, nhưng nhìn chung bạn sẽ muốn tổng kiểm tra chỉ phản ánh nội dung chứ không phải ngày tháng. Ví dụ: nếu tôi touchmột tệp để thay đổi ngày của nó (nhưng không phải nội dung của nó) thì tôi sẽ mong muốn tổng kiểm tra không thay đổi.
Todd Owen


1

Tôi có cùng một vấn đề vì vậy tôi đã đưa ra kịch bản này chỉ liệt kê md5sums của các tệp trong thư mục và nếu nó tìm thấy thư mục con, nó sẽ chạy lại từ đó, để điều này xảy ra, kịch bản phải có thể chạy qua hiện tại thư mục hoặc từ thư mục con nếu đối số đã nói được truyền vào $ 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

Tôi khá chắc chắn rằng tập lệnh này sẽ thất bại nếu tên tệp chứa dấu cách hoặc dấu ngoặc kép. Tôi thấy điều này gây phiền nhiễu với kịch bản bash, nhưng những gì tôi làm là thay đổi IFS.
localhost

1

Nếu bạn muốn thực sự độc lập với các thuộc tính hệ thống tập tin và từ sự khác biệt ở cấp độ bit của một số phiên bản tar, bạn có thể sử dụng cpio:

cpio -i -e theDirname | md5sum

0

Có hai giải pháp nữa:

Tạo nên:

du -csxb /path | md5sum > file

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

Kiểm tra:

du -csxb /path | md5sum -c file

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

0

md5sumlàm việc tốt với tôi, nhưng tôi có vấn đề với sortvà sắp xếp tên tệp. Vì vậy, thay vì tôi sắp xếp theo md5sumkết quả. Tôi cũng cần loại trừ một số tệp để tạo kết quả tương đương.

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.