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.


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  -

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.


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.


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

10

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


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

4

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

cat *.py | md5sum 

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)


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


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


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

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

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

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

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.