Bagaimana saya bisa memeriksa apakah dua file gzip sama?


11

Saya mencoba untuk menghemat ruang saat melakukan backup "bodoh" dengan hanya membuang data ke file teks. Skrip cadangan saya dijalankan setiap hari dan terlihat seperti ini:

  1. Buat direktori dengan nama setelah tanggal cadangan.
  2. Buang beberapa data ke file teks "$name".
  3. Jika file tersebut valid, gzip itu: gzip "$name". Jika tidak rm "$name",.

Sekarang saya ingin menambahkan langkah tambahan untuk menghapus file jika data yang sama juga tersedia di hari sebelumnya (dan buat symlink atau hardlink).

Awalnya saya berpikir untuk menggunakan md5sum "$name", tetapi ini tidak berhasil karena saya juga menyimpan nama file dan tanggal pembuatan.

Apakah gzipada opsi untuk membandingkan dua file yang di-gzip dan beri tahu saya apakah keduanya sama atau tidak? Jika gziptidak memiliki opsi seperti itu, apakah ada cara lain untuk mencapai tujuan saya?



2
Saya akan menyarankan diff <(zcat file1) <(zcat file2), tetapi saran mrethub tentang zdiffterlihat jauh lebih baik.
Kevin

backuppc melakukan untuk Anda apa yang ingin Anda capai secara manual
drone.ah

@ drohne.ah backuppc mungkin agak berlebihan jika hanya satu file per hari ... (Saya kira itu seperti dump SQL di mana itu membuat banyak akal untuk gzip)
mreithub

1
@ mdpc Masalah algoritma di MD5 mungkin tidak relevan. Dimungkinkan untuk membuat tabrakan, tetapi kemungkinan satu-satunya kekhawatiran adalah yang terjadi secara kebetulan, bukan oleh penyerang. Dan itu masih tidak mungkin terjadi sampai Anda memiliki ~ 2 ^ 64 file. Bahkan serangan preimage mungkin tidak masalah.
derobert

Jawaban:


7

Anda dapat menggunakan zcmpatau zdiffseperti yang disarankan mreithub dalam komentarnya (atau perintah Kevin, yang serupa). Ini akan relatif tidak efisien, karena mereka benar-benar mendekompres kedua file dan kemudian meneruskannya ke cmpatau diff. Jika Anda hanya ingin menjawab "mereka sama", Anda mau cmp, itu akan jauh lebih cepat.

Pendekatan Anda dengan md5sumsangat baik, tetapi Anda harus mengambil MD5 sebelum berjalan gzip. Kemudian simpan dalam file di samping file yang dihasilkan .gz. Anda kemudian dapat membandingkan file dengan mudah, sebelum mengompresnya. Jika namanya sama, md5sum -cakan melakukan ini untuk Anda.

$ mkdir "backup1"
$ cd backup1
$ echo "test" > backup-file
$ md5sum backup-file > backup-file.md5
$ gzip -9 backup-file

Dan cadangan selanjutnya:

$ mkdir "backup2"
$ cd backup2
$ echo "test" > backup-file
$ md5sum -c ../backup1/backup-file.md5 
backup-file: OK

Jadi itu belum berubah. OTOH, apakah sudah berubah:

$ echo "different" > backup-file
$ md5sum -c ../backup1/backup-file.md5 
backup-file: FAILED
md5sum: WARNING: 1 computed checksum did NOT match

Jika Anda lolos --quiet, itu hanya akan memberi Anda kode keluar. 0 untuk cocok, non-0 untuk berbeda.

MD5 cukup cepat, tapi tidak begitu. MD4 ( openssl md4adalah yang terbaik yang Anda dapatkan di baris perintah, saya percaya) sekitar dua kali lebih cepat (baik MD5 maupun aman, tetapi keduanya hampir sama tahan tabrakan ketika tidak ada yang mencoba menumbangkannya). SHA-1 ( sha1sum) lebih aman, tetapi lebih lambat; SHA-256 ( sha256sum) aman, tetapi bahkan lebih lambat lagi. CRC32 harus berkali-kali lebih cepat, tetapi lebih pendek dan karenanya akan memiliki lebih banyak tabrakan acak. Ini juga sepenuhnya tidak aman.


zdifftampaknya sia-sia karena saya hanya ingin tahu apakah suatu file telah berubah, bukan apa . zcmpterlihat menarik, saya akan coba itu.
Lekensteyn

7

Jawaban @derobert luar biasa, walaupun saya ingin membagikan beberapa informasi lain yang saya temukan.

gzip -l -v

File yang dikompresi gzip sudah mengandung hash (meskipun tidak aman, lihat posting SO ini ):

$ echo something > foo
$ gzip foo
$ gzip -v -l foo.gz 
method  crc     date  time           compressed        uncompressed  ratio uncompressed_name
defla 18b1f736 Feb  8 22:34                  34                  10 -20.0% foo

Satu dapat menggabungkan CRC dan ukuran terkompresi untuk mendapatkan sidik jari cepat:

gzip -v -l foo.gz | awk '{print $2, $7}'

cmp

Untuk memeriksa apakah dua byte sama atau tidak, gunakan cmp file1 file2. Sekarang, file gzipped memiliki beberapa header dengan data dan footer (CRC plus ukuran asli) ditambahkan. The deskripsi gzip format yang menunjukkan bahwa header berisi waktu ketika file tersebut dikompres dan bahwa nama file adalah string nul-dihentikan yang ditambahkan setelah header 10-byte.

Jadi, dengan asumsi bahwa nama file konstan dan perintah yang sama ( gzip "$name") digunakan, orang dapat memeriksa apakah dua file berbeda dengan menggunakan cmpdan melewatkan byte pertama termasuk waktu:

cmp -i 8 file1 file2

Catatan : asumsi bahwa opsi kompresi yang sama adalah penting, jika tidak maka perintah akan selalu melaporkan file yang berbeda. Ini terjadi karena opsi kompresi disimpan di header dan dapat memengaruhi data yang dikompresi. cmphanya melihat byte mentah dan tidak menafsirkannya sebagai gzip.

Jika Anda memiliki nama file dengan panjang yang sama, maka Anda dapat mencoba menghitung byte yang akan dilewati setelah membaca nama file. Ketika nama file berukuran berbeda, Anda bisa menjalankan cmpsetelah melewatkan byte, seperti cmp <(cut -b9- file1) <(cut -b10- file2).

zcmp

Ini jelas merupakan cara terbaik, pertama-tama memampatkan data dan mulai membandingkan byte dengan cmp(sungguh, inilah yang dilakukan di dalam zcmp( zdiff) shellscript).

Satu catatan, jangan takut dengan catatan berikut di halaman manual:

Ketika kedua file harus terkompresi sebelum perbandingan, yang kedua tidak dikompresi ke / tmp. Dalam semua kasus lain, zdiff dan zcmp hanya menggunakan pipa.

Ketika Anda memiliki Bash yang cukup baru, kompresi tidak akan menggunakan file sementara, hanya sebuah pipa. Atau, seperti zdiffkata sumber itu:

# Reject Solaris 8's buggy /bin/bash 2.03.

Jika byte 4 (FLG) adalah 0 maka nama file tidak ada di header, jadi Anda tidak perlu khawatir tentang panjangnya. Juga, saya menemukan gzip -v -lakan melaporkan waktu file daripada MTIME jika empat byte MTIME di header adalah nol. Perhatikan juga jika MTIME ada di sana, biasanya sedikit sebelum waktu file karena saat kompresi dimulai.
Kitchin

0

Untuk membandingkan dua file gzip, cukup isi, satu perintah, tidak diff, hanya membandingkanmd5sum

$ diff -q <(zcat one.gz|md5sum|cut -f1 -d' ') \
          <(zcat two.gz|md5sum|cut -f1 -d' ') \
    && echo same || echo not_same

Anda juga dapat "memfilter" untuk perbedaan yang relevan,

$ diff -q <(zcat one.gz|grep -v '^-- Dump completed'|md5sum|cut -f1 -d' ') \
          <(zcat two.gz|grep -v '^-- Dump completed'|md5sum|cut -f1 -d' ') \
   && echo same || echo not_same

Jika scripting, saya akan merekomendasikan fungsi filter (tidak diuji, hanya sebuah contoh),

do_filter_sum() {
  zcat $1 | grep -v '^-- Dump completed' | md5sum | cut -f1 -d' '
}

diff -q <(do_filter_sum one.gz) \
        <(do_filter_sum two.gz) \
        && echo same || echo not_same

MD5sum adalah pemborosan, Anda dapat menggunakan cmp. zcatdan grepbisa digabung menjadi zgrep.
Lekensteyn

true, md5sum tidak perlu dibandingkan (kecuali Anda sudah membuatnya); Saya hanya menggunakannya sejak derobert menggunakannya. zgrep hanyalah sebuah skrip yang pada dasarnya melakukan gunzip dan grep (atau sed kasusnya), jadi ada sedikit perbedaan di sana. skrip seperti yang diposting sengaja ditampilkan sebagai rantai pipa dengan bagian yang dapat disambungkan; apa yang menyenangkan dalam menggabungkan semuanya menjadi satu perintah?
michael

1
Dan zcatitu adil gunzip -c. Gunakan alat yang tepat untuk pekerjaan yang tepat, KISS lebih baik daripada mengasapi. Dalam hal ini saya akan menghabiskan waktu saya untuk menulis sesuatu yang menghasilkan tautan keras sesuai kebutuhan, itu lebih menyenangkan.
Lekensteyn
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.