Wie kann ich überprüfen, ob zwei komprimierte Dateien gleich sind?


11

Ich versuche, Platz zu sparen, während ich ein "dummes" Backup mache, indem ich einfach Daten in eine Textdatei kopiere. Mein Backup-Skript wird täglich ausgeführt und sieht folgendermaßen aus:

  1. Erstellen Sie ein Verzeichnis, das nach dem Sicherungsdatum benannt ist.
  2. Speichern Sie einige Daten in einer Textdatei "$name".
  3. Wenn die Datei gültig ist, gzip sie : gzip "$name". Ansonsten , rm "$name".

Jetzt möchte ich einen zusätzlichen Schritt hinzufügen, um eine Datei zu entfernen, wenn dieselben Daten auch am Vortag verfügbar waren (und Symlink oder Hardlink erstellen).

Zuerst habe ich überlegt md5sum "$name", aber das funktioniert nicht, weil ich auch den Dateinamen und das Erstellungsdatum speichere.

Gibt gzipes eine Option, um zwei komprimierte Dateien zu vergleichen und mir zu sagen, ob sie gleich sind oder nicht? Wenn gzipes keine solche Option gibt, gibt es einen anderen Weg, um mein Ziel zu erreichen?


1
Versuchen Sie dies: linux.die.net/man/1/zdiff
mreithub

2
Ich wollte vorschlagen diff <(zcat file1) <(zcat file2), aber Mrethubs Vorschlag zdiffsieht viel besser aus.
Kevin

backuppc macht für Sie, was Sie versuchen, manuell zu erreichen
drone.ah

@ drohne.ah backuppc könnte eine Art Overkill sein, wenn es nur eine Datei pro Tag ist ... (Ich denke, es ist etwas wie ein SQL-Dump, bei dem es sehr sinnvoll ist, gzip zu verwenden)
mreithub

1
@mdpc Die Algorithmusprobleme in MD5 sind wahrscheinlich nicht relevant. Es ist möglich, Kollisionen zu konstruieren, aber wahrscheinlich besteht die einzige Sorge darin, dass sie zufällig und nicht von einem Angreifer verursacht werden. Und das ist immer noch unwahrscheinlich, bis Sie ~ 2 ^ 64 Dateien haben. Selbst ein Preimage-Angriff spielt wahrscheinlich keine Rolle.
Derobert

Antworten:


7

Sie können zcmpoder zdiffwie mreithub in seinem Kommentar vorschlägt (oder Kevins Befehl, der ähnlich ist) verwenden. Diese sind relativ ineffizient, da sie beide Dateien tatsächlich dekomprimieren und dann an cmpoder weitergeben diff. Wenn Sie nur antworten möchten, ob sie gleich sind, möchten Sie, dass cmpes viel schneller geht.

Ihr Ansatz mit dem md5sumist vollkommen gut, aber Sie müssen den MD5 nehmen, bevor Sie laufen gzip. Speichern Sie es dann in einer Datei neben der resultierenden .gzDatei. Sie können die Datei dann einfach vergleichen, bevor Sie sie komprimieren. Wenn der Name derselbe ist, md5sum -cerledigen Sie dies für Sie.

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

Und das nächste Backup:

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

Es hat sich also nicht geändert. OTOH, hatte es sich geändert:

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

Wenn Sie --quietes übergeben, erhalten Sie nur den Exit-Code. 0 für übereinstimmend, nicht 0 für unterschiedlich.

MD5 ist ziemlich schnell, aber nicht besonders schnell. MD4 ( openssl md4ist das Beste, was Sie in der Befehlszeile erhalten, glaube ich) ist ungefähr doppelt so schnell (weder es noch MD5 sind sicher, aber beide sind ungefähr so ​​kollisionssicher, wenn niemand versucht, sie zu untergraben). SHA-1 ( sha1sum) ist sicherer, aber langsamer. SHA-256 ( sha256sum) ist sicher, aber noch langsamer. CRC32 sollte um ein Vielfaches schneller sein, ist jedoch kürzer und weist daher mehr zufällige Kollisionen auf. Es ist auch völlig unsicher.


zdiffscheint eine Verschwendung zu sein, da ich nur wissen möchte, ob sich eine Datei geändert hat, nicht was . zcmpsieht interessant aus, das werde ich versuchen.
Lekensteyn

7

Die Antwort von @derobert ist großartig, obwohl ich einige andere Informationen teilen möchte, die ich gefunden habe.

gzip -l -v

gzip-komprimierte Dateien enthalten bereits einen Hash (allerdings nicht sicher, siehe diesen SO-Beitrag ):

$ 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

Man kann CRC und unkomprimierte Größe kombinieren, um einen schnellen Fingerabdruck zu erhalten:

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

cmp

Verwenden Sie zum Überprüfen, ob zwei Bytes gleich sind oder nicht cmp file1 file2. Jetzt hat eine komprimierte Datei einen Header mit angehängten Daten und Fußzeilen (CRC plus Originalgröße). Die Beschreibung des gzip-Formats zeigt, dass der Header die Zeit enthält, zu der die Datei komprimiert wurde, und dass der Dateiname eine nicht terminierte Zeichenfolge ist, die nach dem 10-Byte-Header angehängt wird.

Unter der Annahme, dass der Dateiname konstant ist und derselbe Befehl ( gzip "$name") verwendet wird, kann überprüft werden, ob zwei Dateien unterschiedlich sind, indem cmpdie ersten Bytes einschließlich der Zeit verwendet und übersprungen werden:

cmp -i 8 file1 file2

Hinweis : Die Annahme, dass dieselben Komprimierungsoptionen wichtig sind, andernfalls meldet der Befehl die Datei immer als unterschiedlich. Dies liegt daran, dass die Komprimierungsoptionen im Header gespeichert sind und sich auf die komprimierten Daten auswirken können. cmpbetrachtet nur rohe Bytes und interpretiert es nicht als gzip.

Wenn Sie Dateinamen gleicher Länge haben, können Sie versuchen, die zu überspringenden Bytes nach dem Lesen des Dateinamens zu berechnen. Wenn die Dateinamen unterschiedlich groß sind, können Sie cmpnach dem Überspringen von Bytes wie z cmp <(cut -b9- file1) <(cut -b10- file2).

zcmp

Dies ist definitiv der beste Weg, es komprimiert zuerst Daten und beginnt, die Bytes mit zu vergleichen cmp(wirklich, das ist, was im zcmp( zdiff) Shellscript gemacht wird).

Ein Hinweis, haben Sie keine Angst vor dem folgenden Hinweis auf der Handbuchseite:

Wenn beide Dateien vor dem Vergleich dekomprimiert werden müssen, wird die zweite in / tmp dekomprimiert. In allen anderen Fällen verwenden zdiff und zcmp nur eine Pipe.

Wenn Sie einen ausreichend neuen Bash haben, wird bei der Komprimierung keine temporäre Datei verwendet, sondern nur eine Pipe. Oder wie die zdiffQuelle sagt:

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

Wenn Byte 4 (FLG) 0 ist, befindet sich der Dateiname nicht im Header, sodass Sie sich keine Gedanken über seine Länge machen müssen. Außerdem habe ich festgestellt, gzip -v -ldass die Dateizeit anstelle von MTIME gemeldet wird, wenn die vier MTIME-Bytes im Header Null sind. Beachten Sie auch, dass MTIME in der Regel etwas vor der Dateizeit liegt, da die Komprimierung gestartet wurde.
Küche

0

Um zwei gzip-Dateien zu vergleichen, nur den Inhalt, einen Befehl, nein diff, nur vergleichenmd5sum

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

Sie können auch nach relevanten Unterschieden "filtern",

$ 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

Bei Skripten würde ich eine Filterfunktion empfehlen (nicht getestet, nur ein Beispiel),

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

Die md5sum ist eine Verschwendung, die Sie verwenden können cmp. zcatund grepkann in zusammengeführt werden zgrep.
Lekensteyn

true, md5sum muss nicht verglichen werden (es sei denn, Sie haben sie bereits generiert). Ich habe es gerade benutzt, seit derobert es benutzt hat. zgrep ist nur ein Skript, das im Grunde genommen Gunzip und Grep ausführt (oder je nach Fall sed), daher gibt es dort kaum einen Unterschied. Das Skript, wie es veröffentlicht wurde, wird absichtlich als Rohrkette mit steckbaren Teilen angezeigt. Was macht es Spaß, alles in einem einzigen Befehl zusammenzuführen?
Michael

1
Und zcatist gerecht gunzip -c. Verwenden Sie das richtige Werkzeug für den richtigen Job, KISS ist besser als aufblähen. In diesem Fall würde ich meine Zeit damit verbringen, etwas zu schreiben, das bei Bedarf harte Links generiert. Das macht mehr Spaß.
Lekensteyn
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.