Bagaimana saya bisa menghitung checksum md5 dari suatu direktori?

133

Saya perlu menghitung checksum md5 ringkasan untuk semua file dari jenis tertentu ( *.pymisalnya) ditempatkan di bawah direktori dan semua sub-direktori.

Apa cara terbaik untuk melakukannya?

Sunting: Solusi yang diusulkan sangat bagus, tetapi ini bukan yang saya butuhkan. Saya mencari solusi untuk mendapatkan ringkasan ringkasan tunggal yang akan secara unik mengidentifikasi direktori secara keseluruhan - termasuk konten dari semua sub-direktori.

victorz
sumber
Lihatlah ini dan ini untuk penjelasan yang lebih rinci.
luvieere
3
Sepertinya pertanyaan superuser bagi saya.
Noldorin
8
Perhatikan bahwa checksum tidak secara unik mengidentifikasi apa pun.
Hosam Aly
1
Mengapa Anda memiliki dua pohon direktori yang mungkin atau mungkin tidak "sama" yang ingin Anda identifikasi secara unik? Apakah file membuat / memodifikasi / mengakses waktu penting? Apakah kontrol versi benar-benar Anda butuhkan?
jmucchiello
Yang benar-benar penting dalam kasus saya adalah kesamaan seluruh isi struktur direktori yang berarti AFAIK sebagai berikut: 1) konten file apa pun di bawah struktur direktori belum diubah 2) tidak ada file baru ditambahkan ke pohon direktori 3) tidak ada file telah dihapus
victorz

Jawaban:

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

Perintah find mencantumkan semua file yang berakhiran .py. MD5sum dihitung untuk setiap file .py. awk digunakan untuk mengambil md5sums (mengabaikan nama file, yang mungkin tidak unik). MD5sum diurutkan. MD5sum dari daftar yang diurutkan ini kemudian dikembalikan.

Saya sudah menguji ini dengan menyalin direktori tes:

rsync -a ~/pybin/ ~/pybin2/

Saya mengganti nama beberapa file di ~ / pybin2.

The find...md5sumperintah mengembalikan output yang sama untuk kedua direktori.

2bcf49a4d19ef9abd284311108d626f1  -
unutbu
sumber
24
Perhatikan bahwa checksum yang sama akan dihasilkan jika file diganti namanya. Jadi ini tidak benar-benar cocok dengan "checksum yang akan secara unik mengidentifikasi direktori secara keseluruhan" jika Anda menganggap tata letak file bagian dari tanda tangan.
Valentin Milea
1
Anda dapat sedikit mengubah baris perintah untuk mengawali setiap checksum file dengan nama file (atau bahkan lebih baik, path relatif file dari / path / ke / dir /) sehingga itu diperhitungkan dalam checksum akhir.
Michael Zilbermann
4
@ zim2001: Ya, itu bisa diubah, tetapi ketika saya mengerti masalahnya (terutama karena komentar OP di bawah pertanyaan), OP ingin dua direktori dianggap sama jika isi file identik tanpa memandang nama file atau bahkan jalur relatif.
unutbu
@unutbu: Saya tahu; Saya bereaksi terhadap catatan sebelumnya, dari Valentin Milea.
Michael Zilbermann
@ValentinMilea hanya menghapus awk ...bagian jika Anda mempertimbangkan tata letak bagian dari tanda tangan.
Segfault
166

Buat file arsip tar dengan cepat dan pipa yang ke md5sum:

tar c dir | md5sum

Ini menghasilkan satu md5sum tunggal yang harus unik untuk pengaturan file dan sub-direktori Anda. Tidak ada file yang dibuat di disk.

ire_and_curses
sumber
25
@CharlesB dengan check-sum tunggal Anda tidak pernah tahu file mana yang berbeda. Pertanyaannya adalah tentang jumlah cek-tunggal untuk suatu direktori.
Hawken
17
ls -alR dir | md5sum. Ini lebih baik tanpa kompresi hanya membaca. Ini unik karena kontennya berisi waktu mod dan ukuran file;)
Sid
14
@ Daps0l - tidak ada kompresi dalam perintah saya. Anda perlu menambahkan zuntuk gzip, atau juntuk bzip2. Saya belum melakukan keduanya.
ire_and_curses
7
Berhati-hatilah dengan melakukan hal ini akan mengintegrasikan timestamp file dan hal-hal lain dalam perhitungan checksum, tidak hanya konten file
Michael Zilbermann
10
Ini lucu, tetapi tidak benar-benar berfungsi. Tidak ada jaminan bahwa tarset file yang sama dua kali, atau pada dua komputer yang berbeda, akan menghasilkan hasil yang persis sama.
fletom
46

Saran ire_and_curses untuk menggunakan tar c <dir>memiliki beberapa masalah:

  • tar memproses entri direktori dalam urutan yang disimpan di sistem file, dan tidak ada cara untuk mengubah urutan ini. Ini secara efektif dapat menghasilkan hasil yang sangat berbeda jika Anda memiliki direktori "sama" di tempat yang berbeda, dan saya tahu tidak ada cara untuk memperbaikinya (tar tidak dapat "mengurutkan" file inputnya dalam urutan tertentu).
  • Saya biasanya peduli tentang apakah angka-angka groupid dan ownerid adalah sama, belum tentu apakah representasi string dari grup / pemilik adalah sama. Ini sesuai dengan apa yang contohnya rsync -a --deletelakukan: ini menyinkronkan hampir semuanya (dikurangi xattrs dan acls), tetapi akan menyinkronkan pemilik dan grup berdasarkan ID mereka, bukan pada representasi string. Jadi, jika Anda menyinkronkan ke sistem yang berbeda yang tidak harus memiliki pengguna / grup yang sama, Anda harus menambahkan --numeric-ownerbendera ke tar
  • tar akan menyertakan nama file direktori yang Anda periksa sendiri, hanya sesuatu yang harus diperhatikan.

Selama tidak ada perbaikan untuk masalah pertama (atau kecuali Anda yakin itu tidak mempengaruhi Anda), saya tidak akan menggunakan pendekatan ini.

The findsolusi berbasis diusulkan di atas juga tidak baik karena mereka hanya menyertakan file, bukan direktori, yang menjadi masalah jika Anda checksumming yang harus diingat direktori kosong.

Akhirnya, sebagian besar solusi yang disarankan tidak mengurutkan secara konsisten, karena susunannya mungkin berbeda di seluruh sistem.

Ini adalah solusi yang saya buat:

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

Catatan tentang solusi ini:

  • Hal LC_ALL=Cini untuk memastikan urutan sortir yang andal di seluruh sistem
  • Ini tidak membedakan antara direktori "bernama \ nwithanewline" dan dua direktori "bernama" dan "withanewline", tetapi kemungkinan terjadinya itu tampaknya sangat tidak mungkin. Seseorang biasanya memperbaiki ini dengan sebuah -print0flag untuk findtetapi karena ada hal-hal lain yang terjadi di sini, saya hanya dapat melihat solusi yang akan membuat perintah lebih rumit maka itu layak.

PS: salah satu sistem saya menggunakan busybox terbatas findyang tidak mendukung -execatau -print0menandai, dan juga menambahkan '/' untuk menunjukkan direktori, sementara findutils menemukan sepertinya tidak, jadi untuk mesin ini saya perlu menjalankan:

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

Untungnya, saya tidak memiliki file / direktori dengan baris baru di namanya, jadi ini bukan masalah pada sistem itu.

Dieter_be
sumber
1
+1: Sangat menarik! Apakah Anda mengatakan bahwa urutannya mungkin berbeda antara jenis sistem file yang berbeda, atau dalam sistem file yang sama?
ire_and_curses
2
kedua. itu hanya tergantung pada urutan entri direktori dalam setiap direktori. Entri direktori AFAIK (dalam sistem file) baru saja dibuat dalam urutan di mana Anda "membuat file dalam direktori". Contoh sederhana: $ mkdir a; sentuh a / file-1; sentuh a / file-2 $ mkdir b; sentuh b / file-2; sentuh b / berkas-1 $ (cd; tar -c | md5sum.) fb29e7af140aeea5a2647974f7cdec77 - $ (cd b;. tar -c | md5sum) a3a39358158a87059b9f111ccffa1023 -
Dieter_be
15

Jika Anda hanya peduli pada file dan tidak mengosongkan direktori, ini berfungsi dengan baik:

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

Demi kelengkapan, ada md5deep (1) ; itu tidak langsung berlaku karena * .py persyaratan filter tetapi harus baik-baik saja bersama dengan find (1).

Michael Shigorin
sumber
Parameter apa yang akan saya gunakan jika saya hanya ingin menghitung checksum md5 dari suatu direktori?
Gabriel Fair
9

Solusi yang paling berhasil bagi saya:

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

Alasan mengapa itu bekerja paling baik untuk saya:

  1. menangani nama file yang berisi spasi
  2. Mengabaikan meta-data filesystem
  3. Mendeteksi apakah file telah diubah namanya

Masalah dengan jawaban lain:

Meta-data Filesystem tidak diabaikan untuk:

tar c - "$path" | md5sum

Tidak menangani nama file yang mengandung spasi atau mendeteksi jika file telah diubah namanya:

find /path -type f | sort -u | xargs cat | md5sum
Tiago Lopo
sumber
4

Jika Anda ingin satu md5sum mencakup seluruh direktori, saya akan melakukan sesuatu seperti

cat *.py | md5sum 
Ramon
sumber
1
Untuk subdir menggunakan sesuatu seperti cat **.py| md5sum
Ramon
3

Periksa semua file, termasuk konten dan nama file mereka

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

Sama seperti di atas, tetapi hanya termasuk file * .py

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

Anda juga dapat mengikuti symlink jika mau

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

Opsi lain yang bisa Anda pertimbangkan untuk digunakan dengan 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)
mengerang
sumber
2

GNU temukan

find /path -type f -name "*.py" -exec md5sum "{}" +;
ghostdog74
sumber
Haruskah token terakhir menjadi \; ?
Dan Moulding
2

Secara teknis Anda hanya perlu menjalankan ls -lR *.py | md5sum. Kecuali jika Anda khawatir tentang seseorang yang memodifikasi file dan menyentuhnya kembali ke tanggal aslinya dan tidak pernah mengubah ukuran file, output dari lsakan memberi tahu Anda jika file telah berubah. Unix-foo saya lemah sehingga Anda mungkin perlu beberapa parameter baris perintah lagi untuk mendapatkan waktu buat dan waktu modifikasi untuk mencetak. lsjuga akan memberi tahu Anda jika izin pada file telah berubah (dan saya yakin ada saklar untuk mematikannya jika Anda tidak peduli tentang itu).

jmucchiello
sumber
3
Ini mungkin cocok dengan beberapa kasus penggunaan, tetapi umumnya Anda ingin agar checksum hanya mencerminkan konten dan bukan tanggal sama sekali. Sebagai contoh, jika saya touchfile untuk mengubah tanggalnya (tetapi tidak isinya) maka saya berharap checksum tidak akan berubah.
Todd Owen
2

Menggunakan md5deep:

md5deep -r FOLDER | awk '{print $1}' | sort | md5sum

tidak benar-benar berubah
sumber
1

Saya mempunyai masalah yang sama jadi saya datang dengan skrip ini yang hanya mencantumkan md5sums dari file dalam direktori dan jika ia menemukan subdirektori ia berjalan lagi dari sana, agar ini terjadi skrip harus dapat dijalankan melalui arus direktori atau dari subdirektori jika argumen tersebut diberikan dalam $ 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
alan
sumber
Saya cukup yakin bahwa skrip ini akan gagal jika nama file mengandung spasi atau kutipan. Saya menemukan ini menjengkelkan dengan skrip bash, tapi yang saya lakukan adalah mengubah IFS.
localhost
1

Jika Anda ingin benar-benar independen dari atribut filesystem dan dari perbedaan level bit dari beberapa versi tar, Anda bisa menggunakan cpio:

cpio -i -e theDirname | md5sum
peterh - Pasang kembali Monica
sumber
0

Ada dua solusi lagi:

Membuat:

du -csxb /path | md5sum > file

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

Memeriksa:

du -csxb /path | md5sum -c file

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

md5sumbekerja dengan baik untuk saya, tetapi saya memiliki masalah dengan sortdan mengurutkan nama file. Jadi alih-alih saya mengurutkan berdasarkan md5sumhasil. Saya juga perlu mengecualikan beberapa file untuk membuat hasil yang sebanding.

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

MonkeyMonkey
sumber