Bagaimana saya mendapatkan jumlah MD5 dari isi direktori sebagai satu jumlah?

171

Program md5sum tidak menyediakan checksum untuk direktori. Saya ingin mendapatkan satu checksum MD5 untuk seluruh isi direktori, termasuk file dalam sub-direktori. Yaitu, satu checksum gabungan yang terbuat dari semua file. Apakah ada cara untuk melakukan ini?


sumber

Jawaban:

186

Cara yang tepat tergantung pada mengapa Anda bertanya:

Opsi 1: Bandingkan Hanya Data

Jika Anda hanya memerlukan hash dari isi file tree, ini akan melakukan trik:

$ find -s somedir -type f -exec md5sum {} \; | md5sum

Ini pertama meringkas semua konten file secara individual, dalam urutan yang dapat diprediksi, kemudian melewati daftar nama file dan hash MD5 untuk di-hash sendiri, memberikan nilai tunggal yang hanya berubah ketika konten salah satu file di pohon berubah.

Sayangnya, find -shanya berfungsi dengan BSD find (1), digunakan di macOS, FreeBSD, NetBSD dan OpenBSD. Untuk mendapatkan sesuatu yang sebanding pada sistem dengan GNU atau SUS find (1), Anda perlu sesuatu yang sedikit lebih jelek:

$ find somedir -type f -exec md5sum {} \; | sort -k 2 | md5sum

Kami telah mengganti find -sdengan panggilan ke sort. The -k 2bit mengatakan itu untuk melewatkan hash MD5, sehingga hanya mengurutkan nama file, yang di lapangan 2 sampai akhir-of-line, dengan sort's hisab.

Ada kelemahan dengan versi perintah ini, yaitu kemungkinan besar menjadi bingung jika Anda memiliki nama file dengan baris baru di dalamnya, karena akan terlihat seperti beberapa baris sortpanggilan. The find -svarian tidak memiliki masalah itu, karena traversal pohon dan penyortiran terjadi dalam program yang sama, find.

Dalam kedua kasus tersebut, penyortiran diperlukan untuk menghindari kesalahan positif: sistem file Unix / Linux yang paling umum tidak mempertahankan daftar direktori dalam urutan yang stabil dan dapat diprediksi. Anda mungkin tidak menyadari ini dari penggunaan lsdan semacamnya, yang secara diam-diam mengurutkan isi direktori untuk Anda. findtanpa -satau sortpanggilan akan mencetak file dalam urutan apa pun yang mengembalikan sistem file yang mendasarinya, yang akan menyebabkan perintah ini untuk memberikan nilai hash yang diubah jika urutan file yang diberikan sebagai perubahan input.

Anda mungkin perlu mengubah md5sumperintah ke md5atau fungsi hash lainnya. Jika Anda memilih fungsi hash lain dan memerlukan bentuk kedua dari perintah untuk sistem Anda, Anda mungkin perlu menyesuaikan sortperintah tersebut. Perangkap lain adalah bahwa beberapa program penjumlah data tidak menuliskan nama file sama sekali, contoh utama adalah sumprogram Unix yang lama .

Metode ini agak tidak efisien, memanggil md5sumN + 1 kali, di mana N adalah jumlah file di pohon, tetapi itu adalah biaya yang diperlukan untuk menghindari hashing metadata file dan direktori.

Opsi 2: Bandingkan Data dan Metadata

Jika Anda harus dapat mendeteksi bahwa segala sesuatu dalam pohon telah berubah, bukan hanya konten file, minta taruntuk mengemas konten direktori untuk Anda, kemudian kirimkan ke md5sum:

$ tar -cf - somedir | md5sum

Karena tarjuga melihat izin file, kepemilikan, dll., Ini juga akan mendeteksi perubahan pada hal-hal tersebut, bukan hanya perubahan pada konten file.

Metode ini jauh lebih cepat, karena hanya membuat satu melewati pohon dan menjalankan program hash hanya sekali.

Seperti findmetode berbasis di atas, tarakan memproses nama file dalam urutan yang mengembalikan sistem file yang mendasarinya. Mungkin dalam aplikasi Anda, Anda dapat yakin bahwa ini tidak akan terjadi. Saya bisa memikirkan setidaknya tiga pola penggunaan yang berbeda di mana itu mungkin terjadi. (Saya tidak akan mencantumkannya, karena kita masuk ke wilayah perilaku yang tidak ditentukan. Setiap sistem file dapat berbeda di sini, bahkan dari satu versi OS ke yang berikutnya.)

Jika Anda mendapati diri Anda mendapatkan hasil positif palsu, saya akan merekomendasikan memilih find | cpioopsi dalam jawaban Gilles .

Warren Young
sumber
7
Saya pikir yang terbaik adalah menavigasi ke direktori yang dibandingkan dan digunakan find .daripada find somedir. Dengan cara ini nama file sama ketika memberikan spesifikasi path yang berbeda untuk ditemukan; ini bisa rumit :-)
Abbafei
Haruskah kita mengurutkan file juga?
CMCDragonkai
@ CMCDragonkai: Apa maksudmu? Dalam kasus pertama, kita lakukan menyortir daftar nama file. Dalam kasus kedua, kami sengaja tidak melakukannya karena bagian dari sesuatu yang ditekankan dalam kalimat pertama adalah bahwa urutan file dalam direktori telah berubah, jadi Anda tidak ingin menyortir apa pun.
Warren Young
@ WarrenYoung Bisakah Anda menjelaskan sedikit lebih menyeluruh mengapa opsi 2 tidak selalu lebih baik? Tampaknya lebih cepat, sederhana dan lebih lintas platform. Dalam hal apa seharusnya itu bukan opsi 1?
Robin Winslow
Alternatif Opsi 1: find somedir -type f -exec sh -c "openssl dgst -sha1 -binary {} | xxd -p" \; | sort | openssl dgst -sha1untuk mengabaikan semua nama file (harus bekerja dengan baris baru)
windm
38

Checksum harus merupakan representasi deterministik dan tidak ambigu dari file sebagai string. Deterministik berarti bahwa jika Anda meletakkan file yang sama di lokasi yang sama, Anda akan mendapatkan hasil yang sama. Tidak ambigu berarti bahwa dua set file yang berbeda memiliki representasi yang berbeda.

Data dan metadata

Membuat arsip berisi file adalah awal yang baik. Ini adalah representasi yang tidak ambigu (jelas, karena Anda dapat memulihkan file dengan mengekstrak arsip). Ini mungkin termasuk file metadata seperti tanggal dan kepemilikan. Namun, ini belum sepenuhnya benar: arsip bersifat ambigu, karena representasinya tergantung pada urutan penyimpanan file, dan jika berlaku pada kompresi.

Solusinya adalah dengan mengurutkan nama file sebelum mengarsipkannya. Jika nama file Anda tidak mengandung baris baru, Anda dapat menjalankan find | sortdaftar itu, dan menambahkannya ke arsip dalam urutan ini. Berhati-hatilah untuk memberi tahu pengarsip agar tidak kembali ke direktori. Berikut adalah contoh dengan POSIX pax, GNU tar dan 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

Hanya nama dan isinya, cara berteknologi rendah

Jika Anda hanya ingin mengambil data file ke dalam akun dan bukan metadata, Anda dapat membuat arsip yang hanya mencakup konten file, tetapi tidak ada alat standar untuk itu. Alih-alih memasukkan konten file, Anda dapat memasukkan hash file. Jika nama file tidak mengandung baris baru, dan hanya ada file dan direktori biasa (tidak ada tautan simbolik atau file khusus), ini cukup mudah, tetapi Anda perlu mengurus beberapa hal:

{ 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

Kami menyertakan daftar direktori selain daftar checksum, karena jika tidak, direktori kosong tidak akan terlihat. Daftar file diurutkan (di tempat yang spesifik dan dapat direproduksi - terima kasih kepada Peter.O untuk mengingatkan saya akan hal itu). echomemisahkan kedua bagian (tanpa ini, Anda bisa membuat beberapa direktori kosong yang namanya mirip dengan md5sumkeluaran yang juga bisa digunakan untuk file biasa). Kami juga menyertakan daftar ukuran file, untuk menghindari serangan ekstensi-panjang .

Omong-omong, MD5 sudah usang. Jika tersedia, pertimbangkan untuk menggunakan SHA-2, atau setidaknya SHA-1.

Nama dan data, mendukung baris baru dalam nama

Berikut adalah varian dari kode di atas yang bergantung pada alat GNU untuk memisahkan nama file dengan null byte. Ini memungkinkan nama file mengandung baris baru. Utilitas digest GNU mengutip karakter khusus dalam output mereka, sehingga tidak akan ada baris baru yang ambigu.

{ 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

Pendekatan yang lebih kuat

Berikut ini adalah skrip Python yang teruji minimal yang membangun hash yang menggambarkan hierarki file. Dibutuhkan direktori dan isi file ke dalam akun dan mengabaikan tautan simbolik dan file lainnya, dan mengembalikan kesalahan fatal jika file apa pun tidak dapat dibaca.

#! /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()
Gilles
sumber
Oke, ini berhasil, terima kasih. Tetapi apakah ada cara untuk melakukannya tanpa memasukkan metadata? Saat ini saya membutuhkannya hanya untuk konten yang sebenarnya.
Bagaimana kalau LC_ALL=C sortmengecek dari lingkungan yang berbeda ... (+ 1 btw)
Peter.O
Anda membuat seluruh program Python untuk ini? Terima kasih! Ini benar-benar lebih dari yang saya harapkan. :-) Bagaimanapun, saya akan memeriksa metode ini serta opsi baru 1 oleh Warren.
Jawaban yang bagus. Mengatur urutan pengurutan LC_ALL=Csangat penting jika dijalankan pada banyak mesin dan OS.
Davor Cubranic
Apa cpio -o -artinya Bukankah cpio menggunakan stdin / out secara default? GNU cpio 2.12 menghasilkancpio: Too many arguments
Jan Tojnar
12

Lihatlah md5deep . Beberapa fitur md5deep yang mungkin menarik bagi Anda:

Operasi rekursif - md5deep dapat memeriksa secara rekursif seluruh pohon direktori. Yaitu, hitung MD5 untuk setiap file dalam direktori dan untuk setiap file di setiap subdirektori.

Mode perbandingan - md5deep dapat menerima daftar hash yang diketahui dan membandingkannya dengan satu set file input. Program dapat menampilkan file input yang cocok dengan daftar hash yang diketahui atau yang tidak cocok.

...

pembuat kesalahan
sumber
Bagus, tetapi tidak bisa membuatnya bekerja, katanya .../foo: Is a directory, apa yang menyebabkannya?
Camilo Martin
3
Pada md5deep sendiri tidak menyelesaikan masalah OP karena tidak mencetak md5sum yang terkonsolidasi, ia hanya mencetak md5sum untuk setiap file dalam direktori. Yang mengatakan, Anda dapat md5sum output md5deep - tidak cukup apa yang diinginkan OP, tetapi dekat! misalnya untuk direktori saat ini: md5deep -r -l -j0 . | md5sum(di mana -rbersifat rekursif, -lberarti "menggunakan jalur relatif" sehingga jalur absolut dari file tidak mengganggu ketika mencoba membandingkan konten dari dua direktori, dan -j0berarti menggunakan 1 utas untuk mencegah non-determinisme karena untuk masing-masing md5sums dikembalikan dalam urutan berbeda).
Stevie
Bagaimana cara mengabaikan beberapa file / direktori di jalur?
Sandeepan Nath
9

Jika tujuan Anda hanya untuk menemukan perbedaan antara dua direktori, pertimbangkan untuk menggunakan diff.

Coba ini:

diff -qr dir1 dir2
Deepak Mittal
sumber
Ya, ini juga berguna. Saya pikir Anda maksud dir1 dir2 dalam perintah itu.
1
Saya biasanya tidak menggunakan GUI ketika saya bisa menghindarinya, tetapi untuk direktori diffing kdiff3 bagus dan juga berfungsi pada banyak platform.
sinelaw
File yang berbeda dilaporkan juga dengan perintah ini.
Serge Stroobandt
7

Anda dapat hash setiap file secara rekursif dan kemudian hash teks yang dihasilkan:

> md5deep -r -l . | sort | md5sum
d43417958e47758c6405b5098f151074 *-

md5deep diperlukan.

Pavel Vlasov
sumber
1
alih-alih md5deepdigunakan hashdeepdi ubuntu 16.04 karena paket md5deep hanyalah dummy transisi untuk hashdeep.
palik
1
Saya sudah mencoba hashdeep. Ini menghasilkan tidak hanya hash tetapi juga beberapa header termasuk ## Invoked from: /home/myuser/dev/yang merupakan jalur Anda saat ini dan ## $ hashdeep -s -r -l ~/folder/. Ini harus disortir, jadi hash terakhir akan berbeda jika Anda mengubah folder atau baris perintah saat ini.
truf
3

Isi file hanya , tidak termasuk nama file

Saya membutuhkan versi yang hanya memeriksa nama file karena isinya berada di direktori yang berbeda.

Versi ini (jawaban Warren Young) banyak membantu, tetapi versi saya md5summenampilkan nama file (relatif terhadap path tempat saya menjalankan perintah), dan nama folder berbeda, oleh karena itu meskipun masing-masing file checksum cocok, checksum akhir tidak 't.

Untuk memperbaikinya, dalam kasus saya, saya hanya perlu menghapus nama file dari setiap baris findoutput (pilih hanya kata pertama yang dipisahkan oleh spasi menggunakan cut):

find -s somedir -type f -exec md5sum {} \; | cut -d" " -f1 | md5sum
Nicole
sumber
Anda mungkin perlu menyortir checksum juga untuk mendapatkan daftar yang dapat direproduksi.
eckes
3

solusi :

$ pip install checksumdir
$ checksumdir -a md5 assets/js
981ac0bc890de594a9f2f40e00f13872
$ checksumdir -a sha1 assets/js
88cd20f115e31a1e1ae381f7291d0c8cd3b92fad

bekerja dengan cepat dan solusi yang lebih mudah daripada bash scripting.

lihat dokumen: https://pypi.python.org/pypi/checksumdir/1.0.5

DmitrySemenov
sumber
jika Anda tidak memiliki pip, Anda mungkin harus menginstalnya dengan yum -y install python-pip (atau dnf / apt-get)
DmitrySemenov
3

nix-hashdari manajer paket Nix

Perintah nix-hash menghitung hash kriptografi dari isi setiap path dan mencetaknya pada output standar. Secara default, ini menghitung hash MD5, tetapi algoritma hash lainnya juga tersedia. Hash dicetak dalam heksadesimal.

Hash dihitung melalui serialisasi setiap jalur: dump dari pohon sistem file yang di-root di path. Ini memungkinkan direktori dan symlink di-hash serta file biasa. Dump dalam format NAR yang diproduksi oleh nix-store --dump. Dengan demikian, jalur nix-hash menghasilkan hash kriptografi yang sama dengan nix-store --dump path | md5sum.

Igor
sumber
2

Saya menggunakan cuplikan ini untuk volume sedang :

find . -xdev -type f -print0 | LC_COLLATE=C sort -z | xargs -0 cat | md5sum -

dan yang ini untuk XXXL :

find . -xdev -type f -print0 | LC_COLLATE=C sort -z | xargs -0 tail -qc100 | md5sum -

poige
sumber
Apa yang dilakukan -xdevbendera?
czerasz
Ini meminta Anda untuk mengetik: man finddan membaca manual yang bagus;)
poige
Poin bagus :-). -xdev Don't descend directories on other filesystems.
czerasz
1
Perhatikan bahwa ini mengabaikan file kosong baru (seperti jika Anda menyentuh file).
RonJohn
Ada banyak kasus di mana ini akan menghasilkan md5sum yang sama dengan struktur file dan direktori yang sama sekali berbeda. Mengganti nama file dan direktori tidak akan mengubahnya sama sekali jika tidak mengubah urutan sortir file. Jadi saya tidak akan merekomendasikan pendekatan ini.
Hans-Peter Störr
2

Pohon check-sum yang baik adalah id pohon Git.

Sayangnya tidak ada alat yang berdiri sendiri yang dapat melakukan itu (setidaknya saya tidak mengetahuinya), tetapi jika Anda memiliki Git, Anda dapat berpura-pura membuat repositori baru dan menambahkan file yang ingin Anda periksa ke indeks.

Ini memungkinkan Anda untuk menghasilkan hash (reproduksi) pohon - yang hanya mencakup konten, nama file, dan beberapa mode file yang diperkecil (dapat dieksekusi).

eckes
sumber
2

Sebagai tindak lanjut dari jawaban yang sangat bagus ini , jika Anda ingin mempercepat perhitungan checksum untuk direktori besar, coba GNU Parallel :

find -s somedir -type f | parallel -k -n 100 md5 {} | md5

(Ini menggunakan Mac dengan md5, ganti sesuai kebutuhan.)

The -kbendera penting, yang menginstruksikan paralleluntuk menjaga ketertiban, jika jumlah keseluruhan dapat berubah dijalankan untuk menjalankan bahkan jika file-file tersebut semua sama. -n 100mengatakan untuk menjalankan setiap instance md5dengan 100 argumen, ini adalah parameter yang dapat Anda atur untuk run time terbaik. Lihat juga -Xbendera parallel(meskipun dalam kasus pribadi saya yang menyebabkan kesalahan.)

shawkinaw
sumber
1

Sebuah skrip yang diuji dengan baik dan mendukung sejumlah operasi termasuk menemukan duplikat, melakukan perbandingan data dan metadata, menunjukkan penambahan serta perubahan dan pemindahan, Anda mungkin menyukai Sidik Jari .

Sidik jari saat ini tidak menghasilkan satu checksum tunggal untuk direktori, tetapi file transkrip yang mencakup checksum untuk semua file dalam direktori itu.

fingerprint analyze

Ini akan menghasilkan index.fingerprintdalam direktori saat ini yang mencakup checksum, nama file, dan ukuran file. Secara default menggunakan keduanya MD5dan SHA1.256.

Di masa depan, saya berharap dapat menambahkan dukungan untuk Merkle Trees ke dalam Sidik Jari yang akan memberi Anda satu checksum tingkat atas. Saat ini, Anda perlu menyimpan file itu untuk melakukan verifikasi.

ioquatix
sumber
1

Saya tidak ingin executable baru atau solusi kikuk jadi inilah pendapat saya:

#!/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
Camilo Martin
sumber
0

Pendekatan yang kuat dan bersih

  • Hal pertama yang pertama, jangan menyimpan memori yang tersedia ! Hash file dalam potongan daripada memberi makan seluruh file.
  • Pendekatan yang berbeda untuk kebutuhan / tujuan yang berbeda (semua yang di bawah ini atau pilih yang pernah berlaku):
    • Hash hanya nama entri dari semua entri di pohon direktori
    • Hash isi file dari semua entri (meninggalkan meta seperti, nomor inode, ctime, atime, mtime, ukuran, dll., Anda mendapatkan ide)
    • Untuk tautan simbolis, isinya adalah nama rujukan. Hash atau pilih untuk lewati
    • Ikuti atau tidak mengikuti (nama terselesaikan) symlink sambil mem-hashing konten entri
    • Jika itu direktori, isinya hanya entri direktori. Ketika melintasi secara rekursif, mereka akan di hash pada akhirnya, tetapi haruskah nama entri direktori pada level tersebut di-hash untuk menandai direktori ini? Bermanfaat dalam kasus penggunaan di mana hash diperlukan untuk mengidentifikasi perubahan dengan cepat tanpa harus melintasi mendalam untuk hash konten. Contohnya adalah perubahan nama file tetapi konten lainnya tetap sama dan semuanya file yang cukup besar
    • Tangani file besar dengan baik (sekali lagi, ingat RAM)
    • Menangani pohon direktori yang sangat dalam (ingat deskriptor file terbuka)
    • Menangani nama file yang tidak standar
    • Bagaimana cara melanjutkan dengan file yang soket, pipa / FIFO, perangkat blok, perangkat char? Harus hash mereka juga?
    • Jangan perbarui waktu akses entri apa pun saat melintasi karena ini akan menjadi efek samping dan kontra-produktif (intuitif?) Untuk kasus penggunaan tertentu.

Ini adalah apa yang saya miliki di atas kepala saya, siapa pun yang telah menghabiskan waktu mengerjakan ini praktis akan menangkap gotchas lainnya dan kasing sudut.

Inilah alat (penafian: Saya kontributor untuk itu) dtreetrawl , sangat ringan pada memori, yang membahas sebagian besar kasus, mungkin agak kasar di tepinya tetapi telah cukup membantu.

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

Contoh keluaran ramah manusia:

...
... //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
enam k
sumber
Saran umum selalu diterima tetapi jawaban terbaik adalah spesifik dan dengan kode yang sesuai. Jika Anda memiliki pengalaman menggunakan alat yang Anda rujuk maka harap sertakan itu.
bu5hman
@ bu5hman Tentu! Saya tidak cukup nyaman mengatakan (senang?) Lebih banyak tentang seberapa baik kerjanya sejak saya terlibat dalam pengembangannya.
enam-k
0

Lakukan secara individual untuk semua file di setiap direktori.

# 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'
Leandro Lima
sumber
0

Migrasi ke format arsip POSIX memengaruhi checksum berbasis GNU Tar

Jawaban ini dimaksudkan sebagai pembaruan tambahan untuk pendekatan penggunaan output Tar untuk hash isi direktori, seperti yang diusulkan (antara lain) dalam jawaban yang sangat baik dari Warren Young dan Gilles beberapa waktu lalu.

Sejak itu, setidaknya openSUSE (sejak dirilis 12.2) mengubah format GNU Tar default dari "GNU tar 1.13.x format" ke format "POSIX 1003.1-2001 (pax)" (sedikit) unggul " . Juga upstream (di antara pengembang GNU Tar) yang mereka diskusikan untuk melakukan migrasi yang sama, lihat misalnya paragraf terakhir di halaman manual GNU Tar ini :

Format default untuk tar GNU ditentukan pada waktu kompilasi. Anda dapat memeriksanya dengan menjalankan tar --help, dan memeriksa baris terakhir dari outputnya. Biasanya, tar GNU dikonfigurasi untuk membuat arsip dalam gnuformat, namun, versi yang akan datang akan beralih ke posix.

(Halaman ini juga memberikan ulasan yang bagus tentang berbagai format arsip yang tersedia dengan GNU Tar.)

Dalam kasus kami, di mana kami menampung isi direktori dan hash hasilnya, dan tanpa mengambil tindakan spesifik, perubahan dari GNU ke format POSIX memiliki konsekuensi sebagai berikut:

  • Meskipun konten direktori identik, checksum yang dihasilkan akan berbeda.

  • Terlepas dari isi direktori yang identik, checksum yang dihasilkan akan berbeda dari menjalankan untuk menjalankan jika header pax default digunakan.

Yang terakhir datang dari fakta, bahwa format POSIX (pax) termasuk header pax diperpanjang yang ditentukan oleh string format yang secara default ke %d/PaxHeaders.%p/%fdalam GNU Tar. Dalam string ini, specifier %pdiganti dengan ID proses dari proses Tar menghasilkan, yang tentu saja berbeda dari menjalankan untuk menjalankan. Lihat bagian manual GNU Tar ini dan khususnya yang ini untuk detailnya.

Baru saja, mulai dari 2019-03-28, ada komitmen yang diterima di hulu yang meredakan masalah ini.

Jadi, untuk dapat terus menggunakan GNU Tar dalam use case yang diberikan, saya dapat merekomendasikan opsi alternatif berikut:

  • Gunakan opsi Tar --format=gnuuntuk secara eksplisit memberi tahu Tar untuk membuat arsip dalam format "lama". Ini wajib untuk memvalidasi checksum "lama".

  • Gunakan format POSIX yang lebih baru, tetapi secara eksplisit tentukan pax header yang sesuai, misalnya oleh --pax-option="exthdr.name=%d/PaxHeaders/%f". Namun, ini memecah kompatibilitas ke belakang ke checksum "lama".

Berikut adalah fragmen kode Bash yang saya gunakan secara teratur untuk menghitung checksum dari isi direktori termasuk metadata:

( 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; )

Di sini, <paths>digantikan oleh daftar path yang terpisah dari semua direktori yang ingin saya bahas oleh checksum. Tujuan dari menggunakan C locale, pemisahan null byte dari nama file, dan menggunakan find dan sort untuk mendapatkan sistem file independen dari file dalam arsip sudah cukup dibahas dalam jawaban lain.

Tanda kurung di sekitarnya menjaga LC_ALLpengaturan lokal dalam subkulit.

Selain itu, saya menggunakan ekspresi ! -type sdengan finduntuk menghindari peringatan dari Tar yang terjadi jika file socket adalah bagian dari isi direktori: GNU Tar tidak mengarsipkan soket. Jika Anda lebih suka diberi tahu tentang soket yang dilewati, tinggalkan ekspresi itu.

Saya gunakan --numeric-ownerdengan Tar, untuk dapat memverifikasi checksum nanti di sistem, di mana tidak semua pemilik file diketahui.

The --atime-preservepilihan untuk Tar lebih baik dihilangkan jika salah satu <paths>kebohongan pada perangkat yang dipasang-hanya membaca. Kalau tidak, Anda akan diperingatkan untuk setiap file tunggal yang stempel waktu aksesnya tidak dapat dipulihkan. Untuk penulisan yang diaktifkan <paths>, saya menggunakan opsi ini, yah, untuk menjaga stempel waktu akses di direktori hash.

Opsi Tar --no-recursion, yang sudah digunakan dalam proposal Gilles , mencegah Tar dari turun secara rekursif ke direktori dengan sendirinya, dan sebagai gantinya mengoperasikan file demi file pada apa pun yang didapat dari findoutput yang diurutkan .

Dan akhirnya, itu tidak benar yang saya gunakan md5sum: Saya benar-benar menggunakan sha256sum.

Jürgen
sumber
-1

Jika Anda tidak membutuhkan md5, Anda dapat mencoba

find . -type f | xargs cksum | cksum
Martin Koubek
sumber
1
Pertanyaan khusus meminta md5
RalfFriedl