La bonne manière dépend exactement de la raison pour laquelle vous demandez:
Option 1: Comparer uniquement les données
Si vous avez juste besoin d'un hachage du contenu du fichier de l'arborescence, ceci fera l'affaire:
$ find -s somedir -type f -exec md5sum {} \; | md5sum
Ceci résume d'abord tout le contenu du fichier individuellement, dans un ordre prévisible, puis transmet cette liste de noms de fichiers et de hachages MD5, en donnant une valeur unique qui ne change que lorsque le contenu d'un des fichiers de l'arborescence est modifié.
Malheureusement, find -s
fonctionne uniquement avec BSD find (1), utilisé dans macOS, FreeBSD, NetBSD et OpenBSD. Pour obtenir quelque chose de comparable sur un système avec GNU ou SUS find (1), vous avez besoin de quelque chose d'un peu plus laid:
$ find somedir -type f -exec md5sum {} \; | sort -k 2 | md5sum
Nous avons remplacé find -s
par un appel à sort
. Le -k 2
bit lui dit de sauter le hachage MD5, donc il ne trie que les noms de fichiers, qui se trouvent dans les champs 2 à la fin de la ligne, en fonction sort
du compte rendu.
Cette version de la commande présente un point faible: elle risque de devenir confuse si vous avez des noms de fichiers contenant des nouvelles lignes, car cela ressemblera à plusieurs lignes à l' sort
appel. La find -s
variante n’a pas ce problème, car la traversée et le tri de l’arbre ont lieu dans le même programme find
,.
Dans les deux cas, le tri est nécessaire pour éviter les faux positifs: les systèmes de fichiers Unix / Linux les plus courants ne conservent pas les listes de répertoires dans un ordre stable et prévisible. Vous pourriez ne pas vous en rendre compte en utilisant ls
, etc., qui trient le contenu du répertoire pour vous. find
sans -s
ou un sort
appel imprimera les fichiers dans l'ordre de leur retour par le système de fichiers sous-jacent, ce qui donnera à cette commande une valeur de hachage modifiée si l'ordre des fichiers qui lui est donné en entrée change.
Vous devrez peut-être modifier les md5sum
commandes md5
ou une autre fonction de hachage. Si vous choisissez une autre fonction de hachage et que vous avez besoin de la seconde forme de la commande pour votre système, vous devrez peut-être ajuster la sort
commande en conséquence. Un autre piège est que certains programmes de sommation de données n'écrivent pas du tout de nom de fichier, un bon exemple étant l'ancien sum
programme Unix .
Cette méthode est quelque peu inefficace, appelant md5sum
N + 1 fois, où N est le nombre de fichiers de l’arborescence, mais c’est un coût nécessaire pour éviter le hachage des métadonnées de fichiers et de répertoires.
Option 2: Comparer les données et les métadonnées
Si vous devez être en mesure de détecter que quelque chose dans une arborescence a changé, pas seulement le contenu du fichier, demandez tar
de compacter le contenu du répertoire, puis envoyez-le à md5sum
:
$ tar -cf - somedir | md5sum
Parce que tar
voit également les autorisations de fichiers, la propriété, etc., cela détectera également les modifications apportées à ces éléments, pas uniquement les modifications apportées au contenu du fichier.
Cette méthode est considérablement plus rapide, puisqu'elle ne fait qu'un seul passage sur l'arborescence et n'exécute le programme de hachage qu'une seule fois.
Comme avec la find
méthode basée ci-dessus, tar
va traiter les noms de fichiers dans l'ordre dans lequel le système de fichiers sous-jacent les renvoie. Il se peut que dans votre application, vous puissiez être sûr que cela ne se produise pas. Je peux penser à au moins trois modèles d'utilisation différents où cela est susceptible d'être le cas. (Je ne vais pas les énumérer, car nous entrons dans un territoire de comportement non spécifié. Chaque système de fichiers peut être différent ici, même d'une version du système d'exploitation à l'autre.)
Si vous trouvez des faux positifs, je vous conseillerais de find | cpio
choisir l' option dans la réponse de Gilles .
find .
place defind somedir
. De cette façon, les noms de fichier sont les mêmes lorsque vous fournissez différentes spécifications de chemin à rechercher; cela peut être délicat :-)find somedir -type f -exec sh -c "openssl dgst -sha1 -binary {} | xxd -p" \; | sort | openssl dgst -sha1
ignorer tous les noms de fichiers (devrait fonctionner avec les nouvelles lignes)La somme de contrôle doit être une représentation déterministe et non ambiguë des fichiers sous forme de chaîne. Déterministe signifie que si vous placez les mêmes fichiers au même endroit, vous obtiendrez le même résultat. Univoque signifie que deux ensembles de fichiers différents ont des représentations différentes.
Données et métadonnées
Faire une archive contenant les fichiers est un bon début. C'est une représentation non ambiguë (évidemment, puisque vous pouvez récupérer les fichiers en extrayant l'archive). Il peut inclure des métadonnées de fichier telles que les dates et la propriété. Cependant, ceci n’est pas encore tout à fait correct: une archive est ambiguë, car sa représentation dépend de l’ordre dans lequel les fichiers sont stockés et, le cas échéant, de la compression.
Une solution consiste à trier les noms de fichiers avant de les archiver. Si vos noms de fichiers ne contiennent pas de saut de ligne, vous pouvez les
find | sort
répertorier et les ajouter aux archives dans cet ordre. Prenez soin de dire à l’archiveur de ne pas récidiver dans les répertoires. Voici des exemples avec POSIXpax
, GNU tar et cpio:Noms et contenu uniquement, la méthode low-tech
Si vous souhaitez uniquement prendre en compte les données du fichier et non les métadonnées, vous pouvez créer une archive qui ne comprend que le contenu du fichier, mais il n'existe aucun outil standard pour cela. Au lieu d'inclure le contenu du fichier, vous pouvez inclure le hachage des fichiers. Si les noms de fichiers ne contiennent pas de saut de ligne et qu'il n'y a que des fichiers et des répertoires normaux (pas de liens symboliques ni de fichiers spéciaux), cela est assez simple, mais vous devez vous occuper de quelques points:
Nous incluons une liste de répertoires en plus de la liste des sommes de contrôle, sinon des répertoires vides seraient invisibles. La liste de fichiers est triée (dans une langue spécifique et reproductible - merci à Peter.O de me l'avoir rappelé).
echo
sépare les deux parties (sans cela, vous pourriez créer des répertoires vides dont le nom ressemble à unemd5sum
sortie et qui pourraient également passer pour des fichiers ordinaires). Nous incluons également une liste des tailles de fichiers, pour éviter les attaques par extension de longueur .À propos, MD5 est obsolète. S'il est disponible, envisagez d'utiliser SHA-2 ou au moins SHA-1.
Noms et données, prenant en charge les nouvelles lignes dans les noms
Voici une variante du code ci-dessus qui repose sur les outils GNU pour séparer les noms de fichiers avec des octets nuls. Cela permet aux noms de fichiers de contenir des nouvelles lignes. Les utilitaires de résumé GNU citent des caractères spéciaux dans leur sortie, il n'y aura donc pas de saut de ligne ambigu.
Une approche plus robuste
Voici un script Python minimalement testé qui crée un hachage décrivant une hiérarchie de fichiers. Il prend les répertoires et le contenu des fichiers dans les comptes, ignore les liens symboliques et les autres fichiers, et renvoie une erreur fatale si un fichier ne peut pas être lu.
la source
LC_ALL=C sort
de vérifier de différents environnements ... (+ 1 btw)LC_ALL=C
est essentiel si vous utilisez plusieurs ordinateurs et plusieurs systèmes d'exploitation.cpio -o -
veut dire? Cpio n'utilise-t-il pas stdin / out par défaut? GNU cpio 2.12 produitcpio: Too many arguments
Jetez un coup d'œil à md5deep . Certaines des fonctionnalités de md5deep qui pourraient vous intéresser:
la source
.../foo: Is a directory
, qu'est-ce qui donne?md5deep -r -l -j0 . | md5sum
(où-r
est récursif,-l
signifie "utiliser des chemins relatifs" afin que le chemin absolu des fichiers n'interfère pas lorsque vous essayez de comparer le contenu de deux répertoires, et-j0
signifie utiliser 1 thread pour éviter le non-déterminisme dû les sommes individuelles md5 étant retournées dans des ordres différents).Si votre objectif est simplement de trouver des différences entre deux répertoires, envisagez d'utiliser diff.
Essaye ça:
la source
Vous pouvez hacher chaque fichier de manière récursive, puis le texte résultant:
md5deep est requis.
la source
md5deep
utiliséhashdeep
sur ubuntu 16.04 car le paquet md5deep est juste un dummy de transition pour hashdeep.## Invoked from: /home/myuser/dev/
votre chemin actuel## $ hashdeep -s -r -l ~/folder/
. Cela doit être trié, donc le hash final sera différent si vous modifiez votre dossier actuel ou votre ligne de commande.Contenu du fichier uniquement , à l'exclusion des noms de fichiers
J'avais besoin d'une version qui ne vérifiait que les noms de fichiers car le contenu se trouvait dans des répertoires différents.
Cette version (la réponse de Warren Young) a beaucoup aidé, mais ma version de
md5sum
sort le nom de fichier (par rapport au chemin depuis lequel la commande a été exécutée), et les noms de dossier étaient différents. Par conséquent, même si les sommes de contrôle du fichier individuel correspondent, 't.Pour résoudre ce problème, dans mon cas, il me suffisait de supprimer le nom du fichier de chaque ligne de la
find
sortie (sélectionnez uniquement le premier mot séparé par des espacescut
):la source
solution :
fonctionne rapide et plus facile solution puis de script bash.
voir doc: https://pypi.python.org/pypi/checksumdir/1.0.5
la source
nix-hash
depuis le gestionnaire de paquets Nixla source
J'utilise cet extrait pour des volumes modérés :
find . -xdev -type f -print0 | LC_COLLATE=C sort -z | xargs -0 cat | md5sum -
et celui-ci pour XXXL :
find . -xdev -type f -print0 | LC_COLLATE=C sort -z | xargs -0 tail -qc100 | md5sum -
la source
-xdev
drapeau?man find
et de lire ce manuel-xdev Don't descend directories on other filesystems.
L'arbre-id de Git est une bonne somme de contrôle d'arbre.
Il n'y a malheureusement pas d'outil autonome disponible pour le faire (du moins je ne le sais pas), mais si vous avez Git à portée de main, vous pouvez simplement prétendre configurer un nouveau référentiel et ajouter les fichiers que vous souhaitez vérifier à l'index.
Cela vous permet de produire le hachage (reproductible) de l’arborescence - qui ne comprend que le contenu, les noms de fichiers et certains modes de fichiers réduits (exécutable).
la source
Pour donner suite à cette excellente réponse , si vous souhaitez accélérer le calcul de la somme de contrôle pour un répertoire volumineux, essayez GNU Parallel :
(Ceci utilise un Mac avec
md5
, remplacez si nécessaire.)L’
-k
indicateur est important car il indique que l’ordreparallel
doit être maintenu, sinon la somme globale peut changer d’exécution même si les fichiers sont tous identiques.-n 100
dit d’exécuter chaque instance demd5
100 arguments, c’est un paramètre que vous pouvez modifier pour obtenir le meilleur temps d’exécution. Voir aussi-X
drapeau deparallel
(bien que dans mon cas personnel cela ait causé une erreur.)la source
Un script bien testé qui prend en charge un certain nombre d'opérations, notamment la recherche de doublons, la comparaison de données et de métadonnées, l'affichage d'ajouts, de modifications et de suppressions, pourrait vous intéresser .
À l'heure actuelle, les empreintes digitales ne produisent pas une somme de contrôle unique pour un répertoire, mais un fichier de transcription qui inclut les sommes de contrôle pour tous les fichiers de ce répertoire.
Cela générera
index.fingerprint
dans le répertoire actuel qui inclut les sommes de contrôle, les noms de fichiers et la taille des fichiers. Par défaut, il utilise les deuxMD5
etSHA1.256
.À l'avenir, j'espère ajouter un support pour les arbres Merkle dans Fingerprint, ce qui vous donnera une somme de contrôle de niveau supérieur. Pour le moment, vous devez conserver ce fichier pour procéder à la vérification.
la source
Je ne voulais pas de nouveaux exécutables ni de solutions maladroites alors voici ce que je pense:
la source
Une approche robuste et propre
C’est ce que j’ai en tête: quiconque a passé du temps à travailler là-dessus aurait attrapé d’autres pièges et autres cas.
Voici un outil (disclaimer: j'y contribue) dtreetrawl , très léger sur la mémoire, ce qui, dans la plupart des cas, peut sembler un peu approximatif, mais a été très utile.
Un exemple de sortie conviviale:
la source
Faire individuellement pour tous les fichiers de chaque répertoire.
la source
La migration vers le format d'archive POSIX affecte les sommes de contrôle basées sur GNU Tar
Cette réponse se veut une mise à jour supplémentaire de l'approche consistant à utiliser la sortie Tar pour hacher le contenu des répertoires, comme cela avait été proposé (entre autres) dans les excellentes réponses de Warren Young et Gilles il y a quelque temps.
Depuis lors, au moins openSUSE (depuis sa version 12.2) a changé son format GNU Tar par défaut du format "GNU tar 1.13.x" au format (légèrement) supérieur "Format POSIX 1003.1-2001 (pax)" . En amont également (parmi les développeurs de GNU Tar), ils discutent de la même migration, voir par exemple le dernier paragraphe de cette page du manuel de GNU Tar :
(Cette page donne également un bon aperçu des différents formats d’archives disponibles avec GNU Tar.)
Dans notre cas, où nous tarifions le contenu du répertoire et hachaîmes le résultat, et sans prendre de mesures spécifiques, le passage du format GNU au format POSIX a les conséquences suivantes:
Malgré un contenu de répertoire identique, la somme de contrôle obtenue sera différente.
Malgré un contenu de répertoire identique, la somme de contrôle obtenue sera différente d'une exécution à l'autre si les en-têtes pax par défaut sont utilisés.
Ce dernier provient du fait que le format POSIX (pax) inclut des en-têtes de pax étendus qui sont déterminés par une chaîne de format par défaut
%d/PaxHeaders.%p/%f
dans GNU Tar. Dans cette chaîne, le spécificateur%p
est remplacé par l'ID de processus du processus Tar générant, qui est bien sûr différent d'une exécution à l'autre. Voir cette section du manuel GNU Tar et en particulier celle-ci pour plus de détails.En ce moment, datant du 2019-03-28, il existe un commit accepté en amont qui désamorce ce problème.
Donc, pour pouvoir continuer à utiliser GNU Tar dans le cas d'utilisation donné, je peux recommander les options alternatives suivantes:
Utilisez l'option Tar
--format=gnu
pour indiquer explicitement à Tar de générer l'archive au format "ancien". Ceci est obligatoire pour valider les "anciennes" sommes de contrôle.Utilisez le format POSIX plus récent, mais spécifiez explicitement un en-tête pax approprié, par exemple, par
--pax-option="exthdr.name=%d/PaxHeaders/%f"
. Cependant, cela rompt la compatibilité avec les "anciennes" sommes de contrôle.Voici un fragment de code Bash que j'utilise régulièrement pour calculer la somme de contrôle du contenu du répertoire, y compris les métadonnées:
Ici,
<paths>
est remplacée par une liste d'espaces des chemins de tous les répertoires que je veux voir couverts par la somme de contrôle. Le but d'utiliser les paramètres régionaux C, la séparation des noms de fichiers avec un octet nul et d'utiliser find et sort pour obtenir un ordre indépendant du système de fichiers des fichiers de l'archive est déjà suffisamment explicité dans les autres réponses.Les parenthèses environnantes conservent le
LC_ALL
paramètre local dans un sous-shell.De plus, j'utilise l'expression
! -type s
avecfind
pour éviter les avertissements de Tar qui se produisent si les fichiers de socket font partie du contenu du répertoire: GNU Tar n'archive pas les sockets. Si vous préférez être averti des sockets ignorés, laissez cette expression de côté.J'utilise
--numeric-owner
avec Tar pour pouvoir vérifier les sommes de contrôle plus tard, même sur des systèmes où tous les propriétaires de fichiers ne sont pas connus.L'
--atime-preserve
option pour Tar est mieux omise si l'un des<paths>
repose sur un périphérique monté en lecture seule. Sinon, vous serez averti pour chaque fichier dont l'horodatage d'accès n'a pas pu être restauré par Tar. Pour l'écriture activée<paths>
, j'utilise cette option, eh bien, pour conserver les horodatages d'accès dans les répertoires hachés.L’option Tar
--no-recursion
, qui était déjà utilisée dans la proposition de Gilles , empêche Tar de redescendre de manière récursive dans des répertoires et d’opérer à la place fichier par fichier sur tout ce qui est alimenté par lafind
sortie triée .Et enfin, ce n’est pas vrai que j’utilise
md5sum
: j’utilisesha256sum
.la source
Si vous n’avez pas besoin de md5, vous pouvez essayer
la source