Як я можу перевірити, чи однакові два файли gzipped?


11

Я намагаюся заощадити місце, роблячи "тупу" резервну копію, просто завантажуючи дані в текстовий файл. Мій сценарій резервного копіювання виконується щодня і виглядає приблизно так:

  1. Створіть каталог, названий за датою резервного копіювання.
  2. Скиньте деякі дані в текстовий файл "$name".
  3. Якщо файл є дійсним, GZIP його: gzip "$name". В іншому випадку rm "$name".

Тепер я хочу додати додатковий крок для видалення файлу, якщо ті самі дані також були доступні напередодні (і створити символьне посилання або жорстке посилання).

Спочатку я думав використовувати md5sum "$name", але це не працює, оскільки я також зберігаю ім'я файлу та дату створення.

Чи gzipє можливість порівняти два gzipped файли та сказати мені, чи вони рівні чи ні? Якщо gzipтакого варіанту немає, чи є інший спосіб досягти своєї мети?


1
Спробуйте це: linux.die.net/man/1/zdiff
mreithub

2
Я збирався запропонувати diff <(zcat file1) <(zcat file2), але пропозиція mrethub zdiffвиглядає набагато краще.
Кевін

backuppc робить для вас те, чого ви намагаєтеся досягти вручну
drone.ah

@ drohne.ah backuppc може виявитися надмірним набором, якщо це лише один файл на день ... (Я думаю, що це схоже на дамп SQL, де має багато сенсу gzip)
mreithub

1
@mdpc Проблеми з алгоритмом у MD5, ймовірно, не актуальні. Можна зібрати зіткнення, але, швидше за все, турбують лише ті випадки, які трапляються випадково, а не зловмисником. І це все одно навряд чи станеться, поки у вас немає ~ 2 ^ 64 файлів. Навіть попередня атака, мабуть, не має значення.
дероберт

Відповіді:


7

Ви можете використовувати zcmpабо zdiffяк пропонує mreithub у своєму коментарі (або команду Кевіна, яка схожа). Вони будуть відносно неефективними, оскільки вони фактично розпаковують обидва файли, а потім передають їх у cmpабо diff. Якщо ви просто хочете відповісти "вони однакові", ви хочете cmp, це буде набагато швидше.

Ваш підхід до системи md5sumідеально хороший, але вам потрібно взяти MD5 перед запуском gzip. Потім збережіть його у файлі поряд із отриманим .gzфайлом. Потім ви можете легко порівняти файл, перш ніж його стискати. Якщо ім’я те саме, md5sum -cзробимо це за вас.

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

І наступне резервне копіювання:

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

Отже, це не змінилося. OTOH, чи змінилося це:

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

Якщо ви перейдете --quietдо нього, він просто дасть вам вихідний код. 0 для відповідних, не-0 для відмінних.

MD5 досить швидкий, але не надзвичайно. openssl md4Я вважаю, що MD4 ( найкращий варіант, який ви отримуєте в командному рядку) приблизно вдвічі швидший (ані він, ані MD5 не захищений, але обидва є настільки ж стійкими до зіткнення, коли ніхто не намагається їх підривати). SHA-1 ( sha1sum) надійніше, але повільніше; SHA-256 ( sha256sum) надійний, але ще повільніше. CRC32 повинен бути в багато разів швидшим, але коротшим і, таким чином, матиме більше випадкових зіткнень. Це також цілком небезпечно.


zdiffздається марною, тому що я просто хочу знати, чи змінився файл, а не що . zcmpвиглядає цікаво, я спробую це.
Лекенштейн

7

Відповідь @derobert чудова, хоча я хочу поділитися іншою інформацією, яку я знайшов.

gzip -l -v

Файли, стиснуті gzip, містять уже хеш (однак не захищено, див. цю публікацію ТА ):

$ 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

Можна комбінувати CRC та нестиснений розмір, щоб отримати швидкий відбиток пальця:

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

cmp

Щоб перевірити, чи два байти рівні чи ні, використовуйте cmp file1 file2. Тепер у файлі gzipped є якийсь заголовок із доданими даними та колонтитулом (CRC плюс оригінальний розмір). Опис формату GZIP показує , що заголовок містить час , коли файл був стиснутий і що ім'я файлу є NUL-завершеною рядком , яка додається після заголовка 10 байт.

Отже, припускаючи, що ім'я файлу є постійним і gzip "$name"використовується одна і та ж команда ( ), можна перевірити, чи відрізняються два файли, використовуючи cmpта пропускаючи перші байти, включаючи час:

cmp -i 8 file1 file2

Примітка : припущення про те, що важливі однакові параметри стиснення, інакше команда завжди буде повідомляти файл як інший. Це відбувається тому, що параметри стиснення зберігаються у заголовку і можуть впливати на стислі дані. cmpпросто дивиться на необроблені байти і не трактує це як gzip.

Якщо у вас є назви файлів однакової довжини, ви можете спробувати обчислити байти, які слід пропустити після читання імені файлу. Якщо назви файлів мають різний розмір, ви можете працювати cmpпісля пропускання байтів, наприклад cmp <(cut -b9- file1) <(cut -b10- file2).

zcmp

Це, безумовно, найкращий шлях, він спочатку стискає дані і починає порівнювати байти з cmp(дійсно, це робиться в zcmp(( zdiff) оболонці).

Одна примітка, не бійтеся наступної примітки на сторінці керівництва:

Коли обидва файли повинні бути нестисненими перед порівнянням, другий не стискається до / tmp. У всіх інших випадках videff та zcmp використовують лише трубу.

Коли у вас є достатньо новий Bash, для стиснення не буде використовуватися тимчасовий файл, а лише труба. Або, як zdiffкаже джерело:

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

Якщо байт 4 (FLG) дорівнює 0, то ім'я файлу відсутнє в заголовку, тому вам не потрібно турбуватися про його довжину. Крім того, я виявив gzip -v -l, що звітує про час файлу замість MTIME, якщо чотири байти MTIME у заголовку дорівнюють нулю. Також зверніть увагу, якщо MTIME є, він, як правило, трохи раніше часу файлу, тому що саме тоді починається стиснення.
котлін

0

Для порівняння двох файлів gzip, лише вміст, одна команда, ні diff, просто порівнянняmd5sum

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

Ви також можете "фільтрувати" відповідні відмінності,

$ 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

Якщо сценарій, я рекомендую функцію фільтра (не перевірена, лише приклад),

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 - це відхід, який можна використовувати cmp. zcatі grepможуть бути об'єднані в zgrep.
Лекенштейн

правда, md5sum не потрібно порівнювати (якщо ви вже не створили їх); Я просто використовував його з тих пір, як користувався дероберт. zgrep - це лише сценарій, який в основному робить gunzip і grep (або sed залежно від випадку), тому різниці там мало. розміщений сценарій навмисно відображається у вигляді ланцюга труб із підключеними деталями; яка радість у злитті всього в одну команду?
Майкл

1
І zcatпросто gunzip -c. Використовуйте правильний інструмент для правильної роботи, KISS краще, ніж роздуття. У цьому випадку я витратив би свій час на написання чогось, що створює жорсткі посилання за необхідності, це веселіше.
Лекенштейн
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.