Comment puis-je vérifier si deux fichiers gzippés sont égaux?


11

J'essaie d'économiser de l'espace tout en faisant une sauvegarde "stupide" en déversant simplement les données dans un fichier texte. Mon script de sauvegarde est exécuté quotidiennement et ressemble à ceci:

  1. Créez un répertoire nommé d'après la date de sauvegarde.
  2. Vider certaines données dans un fichier texte "$name".
  3. Si le fichier est valide, gzipper: gzip "$name". Dans le cas contraire, rm "$name".

Maintenant, je veux ajouter une étape supplémentaire pour supprimer un fichier si les mêmes données étaient également disponibles la veille (et créer un lien symbolique ou un lien physique).

Au début, j'ai pensé à utiliser md5sum "$name", mais cela ne fonctionne pas car je stocke également le nom de fichier et la date de création.

A gzipune option pour comparer deux fichiers compressés et me dire s'ils sont égaux ou non? Si ce gzipn'est pas le cas, existe-t-il un autre moyen d'atteindre mon objectif?



2
J'allais suggérer diff <(zcat file1) <(zcat file2), mais la suggestion de mrethub de zdiffsemble beaucoup mieux.
Kevin

backuppc fait pour vous ce que vous essayez de réaliser manuellement
drone.ah

@ drohne.ah backuppc pourrait être un peu exagéré s'il ne s'agit que d'un fichier par jour ... (je suppose que c'est comme un vidage SQL où il est très logique de gzip)
mreithub

1
@mdpc Les problèmes d'algorithme dans MD5 ne sont probablement pas pertinents. Il est possible de construire des collisions, mais la seule préoccupation est probablement celles qui se produisent par hasard, pas par un attaquant. Et il est peu probable que cela se produise jusqu'à ce que vous ayez ~ 2 ^ 64 fichiers. Même une attaque de pré-image n'a probablement pas d'importance.
derobert

Réponses:


7

Vous pouvez utiliser zcmpou zdiffcomme mreithub le suggère dans son commentaire (ou la commande de Kevin, qui est similaire). Celles-ci seront relativement inefficaces, car elles décompressent les deux fichiers, puis les transmettent à cmpou diff. Si vous voulez juste répondre "sont-ils les mêmes", vous voulez cmp, ce sera beaucoup plus rapide.

Votre approche avec le md5sumest parfaitement bonne, mais vous devez prendre le MD5 avant de courir gzip. Ensuite, stockez-le dans un fichier avec le .gzfichier résultant . Vous pouvez ensuite comparer facilement le fichier avant de le compresser. Si le nom est le même, le md5sum -cfera pour vous.

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

Et la prochaine sauvegarde:

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

Cela n'a donc pas changé. OTOH, avait-il changé:

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

Si vous y passez --quiet, il vous donnera simplement le code de sortie. 0 pour apparié, non 0 pour différé.

MD5 est assez rapide, mais pas de façon éclatante. MD4 ( openssl md4est le meilleur que vous obtenez sur la ligne de commande, je crois) est environ deux fois plus rapide (ni lui ni MD5 ne sont sécurisés, mais les deux sont à peu près aussi résistants aux collisions lorsque personne ne tente de les renverser). SHA-1 ( sha1sum) est plus sûr, mais plus lent; SHA-256 ( sha256sum) est sécurisé, mais encore plus lent. CRC32 devrait être beaucoup plus rapide, mais est plus court et aura donc plus de collisions aléatoires. C'est aussi totalement dangereux.


zdiffsemble un gaspillage car je veux juste savoir si un fichier a changé, pas quoi . zcmpsemble intéressant, je vais essayer ça.
Lekensteyn

7

La réponse de @derobert est excellente, bien que je veuille partager d'autres informations que j'ai trouvées.

gzip -l -v

Les fichiers compressés avec gzip contiennent déjà un hachage (mais pas sécurisé, voir ce message SO ):

$ 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

On peut combiner le CRC et la taille non compressée pour obtenir une empreinte digitale rapide:

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

cmp

Pour vérifier si deux octets sont égaux ou non, utilisez cmp file1 file2. Maintenant, un fichier compressé a un en-tête avec les données et le pied de page (CRC plus la taille d'origine) ajoutés. La description du format gzip montre que l'en-tête contient l'heure à laquelle le fichier a été compressé et que le nom du fichier est une chaîne terminée par zéro qui est ajoutée après l'en-tête de 10 octets.

Ainsi, en supposant que le nom de fichier est constant et que la même commande ( gzip "$name") est utilisée, on peut vérifier si deux fichiers sont différents en utilisant cmpet en sautant les premiers octets, y compris l'heure:

cmp -i 8 file1 file2

Remarque : l'hypothèse selon laquelle les mêmes options de compression sont importantes, sinon la commande signalera toujours le fichier comme différent. Cela se produit car les options de compression sont stockées dans l'en-tête et peuvent affecter les données compressées. cmpregarde juste les octets bruts et ne l'interprète pas comme gzip.

Si vous avez des noms de fichiers de la même longueur, vous pouvez essayer de calculer les octets à ignorer après avoir lu le nom du fichier. Lorsque les noms de fichiers sont de taille différente, vous pouvez exécuter cmpaprès avoir ignoré les octets, comme cmp <(cut -b9- file1) <(cut -b10- file2).

zcmp

C'est certainement la meilleure façon de procéder, il compresse d'abord les données et commence à comparer les octets avec cmp(vraiment, c'est ce qui est fait dans le shellscript zcmp( zdiff)).

Une note, n'ayez pas peur de la note suivante dans la page de manuel:

Lorsque les deux fichiers doivent être décompressés avant la comparaison, le second est décompressé dans / tmp. Dans tous les autres cas, zdiff et zcmp utilisent uniquement un canal.

Lorsque vous avez un Bash suffisamment nouveau, la compression n'utilisera pas de fichier temporaire, juste un tube. Ou, comme le dit la zdiffsource:

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

Si l'octet 4 (FLG) vaut 0, le nom du fichier n'est pas dans l'en-tête, vous n'avez donc pas à vous soucier de sa longueur. En outre, j'ai trouvé gzip -v -lsignalera l'heure du fichier au lieu de MTIME si les quatre octets MTIME dans l'en-tête sont nuls. Notez également que si MTIME est là, c'est généralement un peu avant l'heure du fichier car c'est lorsque la compression a commencé.
kitchin

0

Pour comparer deux fichiers gzip, juste le contenu, une commande, non diff, simplement comparermd5sum

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

Vous pouvez également "filtrer" les différences pertinentes,

$ 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

En cas de script, je recommanderais une fonction de filtre (non testée, juste un exemple),

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

Le md5sum est un déchet, vous pouvez l'utiliser cmp. zcatet greppeut être fusionné en zgrep.
Lekensteyn

true, md5sum n'est pas nécessaire de comparer (sauf si vous les avez déjà générés); Je viens de l'utiliser depuis que derobert l'a utilisé. zgrep est juste un script qui fait essentiellement gunzip et grep (ou sed selon le cas), il n'y a donc que peu de différence. le script tel que publié est intentionnellement montré comme une chaîne de tuyaux avec des pièces enfichables; quel est le plaisir de tout fusionner en une seule commande?
michael

1
Et zcatc'est juste gunzip -c. Utilisez le bon outil pour le bon travail, KISS est meilleur que ballonnement. Dans ce cas, je passerais mon temps à écrire quelque chose qui génère des liens durs au besoin, c'est plus amusant.
Lekensteyn
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.