web-dev-qa-db-fra.com

Comment calculer une somme de contrôle md5 d'un répertoire?

J'ai besoin de calculer une somme de contrôle md5 récapitulative pour tous les fichiers d'un type particulier (*.py par exemple) placés dans un répertoire et tous les sous-répertoires.

Quelle est la meilleure façon de le faire?

Edit: Les solutions proposées sont très gentilles, mais ce n’est pas exactement ce dont j’ai besoin. Je cherche une solution pour obtenir un sommaire unique somme de contrôle qui identifiera de manière unique le répertoire dans son ensemble, y compris le contenu de tous ses sous-répertoires.

121
victorz
find /path/to/dir/ -type f -name "*.py" -exec md5sum {} + | awk '{print $1}' | sort | md5sum

La commande find répertorie tous les fichiers se terminant par .py . Le md5sum est calculé pour chaque fichier .py. awk est utilisé pour enlever les sommes md5 (en ignorant les noms de fichiers, qui peuvent ne pas être uniques) . Les sommes md5 sont triées .

J'ai testé cela en copiant un répertoire de test:

rsync -a ~/pybin/ ~/pybin2/

J'ai renommé certains fichiers dans ~/pybin2.

La commande find...md5sum renvoie le même résultat pour les deux répertoires.

2bcf49a4d19ef9abd284311108d626f1  -
143
unutbu

Créez un fichier archive tar à la volée et dirigez-le vers md5sum:

tar c dir | md5sum

Cela produit une seule somme md5 qui devrait être unique pour la configuration de vos fichiers et sous-répertoires. Aucun fichier n'est créé sur le disque.

158
ire_and_curses

la suggestion de ire_and_curses d'utiliser tar c <dir> pose quelques problèmes:

  • tar traite les entrées de répertoire dans l'ordre dans lequel elles sont stockées dans le système de fichiers, et il n'y a aucun moyen de changer cet ordre. Cela peut effectivement produire des résultats complètement différents si vous avez le "même" répertoire à différents endroits et je ne sais pas comment résoudre ce problème (tar ne peut pas "trier" ses fichiers d'entrée dans un ordre particulier).
  • Je me soucie généralement de savoir si les numéros de groupe et de propriétaire sont les mêmes, pas nécessairement si la représentation sous forme de chaîne de groupe/propriétaire est la même. Ceci correspond à ce que fait par exemple rsync -a --delete: il synchronise pratiquement tout (moins xattrs et acls), mais il synchronise le propriétaire et le groupe en fonction de leur ID, et non de la représentation sous forme de chaîne. Donc, si vous avez synchronisé vers un système différent qui n'a pas nécessairement les mêmes utilisateurs/groupes, vous devez ajouter l'indicateur --numeric-owner à tar.
  • tar inclura le nom du fichier du répertoire que vous vérifiez lui-même, juste quelque chose à connaître.

Tant qu'il n'y a pas de solution pour le premier problème (ou si vous n'êtes pas sûr que cela ne vous concerne pas), je n'utiliserais pas cette approche.

Les solutions basées sur find proposées ci-dessus ne sont pas non plus valables, car elles n'incluent que des fichiers, pas des répertoires, ce qui pose problème si vous devez garder à l'esprit les répertoires vides.

Enfin, la plupart des solutions suggérées ne trient pas systématiquement, car le classement peut être différent d’un système à l’autre.

Voici la solution que j'ai trouvée:

dir=<mydir>; (find "$dir" -type f -exec md5sum {} +; find "$dir" -type d) | LC_ALL=C sort | md5sum

Notes sur cette solution:

  • Le LC_ALL=C permet de garantir un ordre de tri fiable entre les systèmes
  • Cela ne fait pas la différence entre un répertoire "nommé\nwithanewline" et deux répertoires "nommés" et "withanewline", mais la probabilité que cela se produise semble très improbable. On résout généralement cela avec un drapeau -print0 pour find, mais comme il se passe d'autres choses ici, je ne vois que des solutions qui rendraient la commande plus compliquée qu'elle ne valait la peine.

PS: L’un de mes systèmes utilise une find (nombre limité) busybox qui ne prend pas en charge les drapeaux -exec et -print0. Il ajoute également un «/» pour indiquer les répertoires, alors que find ne semble pas le trouver.

dir=<mydir>; (find "$dir" -type f | while read f; do md5sum "$f"; done; find "$dir" -type d | sed 's#/$##') | LC_ALL=C sort | md5sum

Heureusement, je n'ai pas de fichiers/répertoires avec des nouvelles lignes dans leurs noms, donc ce n'est pas un problème sur ce système.

44
Dieter_be

Si vous ne vous souciez que des fichiers et non des répertoires vides, cela fonctionne bien:

find /path -type f | sort -u | xargs cat | md5sum
13
Simon Guest

Par souci d’exhaustivité, il y a md5deep (1) ; ce n'est pas directement applicable en raison de l'exigence de filtre * .py mais devrait très bien fonctionner avec find (1).

10
Michael Shigorin

Une solution qui a fonctionné le mieux pour moi:

find "$path" -type f -print0 | sort -z | xargs -r0 md5sum | md5sum

Raison pour laquelle cela a fonctionné le mieux pour moi:

  1. gère les noms de fichiers contenant des espaces
  2. Ignore les méta-données du système de fichiers
  3. Détecte si le fichier a été renommé

Problèmes avec d'autres réponses:

Les métadonnées du système de fichiers ne sont pas ignorées pour: 

tar c - "$path" | md5sum

Ne gère pas les noms de fichiers contenant des espaces et ne détecte pas si le fichier a été renommé:

find /path -type f | sort -u | xargs cat | md5sum
9
Tiago Lopo

Somme de contrôle de tous les fichiers, y compris le contenu et leurs noms

grep -ar -e . /your/dir | md5sum | cut -c-32

Comme ci-dessus, mais n'incluant que les fichiers * .py

grep -ar -e . --include="*.py" /your/dir | md5sum | cut -c-32

Vous pouvez également suivre les liens symboliques si vous le souhaitez 

grep -aR -e . /your/dir | md5sum | cut -c-32

Autres options que vous pourriez envisager d'utiliser avec grep

-s, --no-messages         suppress error messages
-D, --devices=ACTION      how to handle devices, FIFOs and sockets;
-Z, --null                print 0 byte after FILE name
-U, --binary              do not strip CR characters at EOL (MSDOS/Windows)
3
moander

Si vous voulez une somme md5 couvrant tout le répertoire, je ferais quelque chose comme

cat *.py | md5sum 
3
Ramon

Recherche GNU

find /path -type f -name "*.py" -exec md5sum "{}" +;
2
ghostdog74

Techniquement, vous devez seulement exécuter ls -lR *.py | md5sum. À moins que vous ne craigniez que quelqu'un modifie les fichiers et les ramène à leur date d'origine sans jamais changer la taille des fichiers, la sortie de ls devrait vous dire si le fichier a été modifié. Mon unix-foo est faible, vous aurez donc peut-être besoin de plus de paramètres de ligne de commande pour obtenir l'heure de création et l'heure de modification pour l'impression. ls vous indiquera également si les autorisations sur les fichiers ont changé (et je suis sûr qu'il existe des commutateurs pour désactiver cette option si vous ne vous en souciez pas).

2
jmucchiello

J'utilise HashCopy pour faire cela. Il peut générer et vérifier MD5 et SHA sur un seul fichier ou un répertoire. Il peut être téléchargé à partir de www.jdxsoftware.org.

2
William Leng

Utiliser md5deep:

md5deep -r FOLDER | awk '{print $1}' | sort | md5sum

2
doesntreallymatter

J'ai eu le même problème alors je suis venu avec ce script qui liste simplement les sommes md5 des fichiers dans le répertoire et s'il trouve un sous-répertoire, il se lance à nouveau à partir de là, pour que cela se produise, le script doit pouvoir être lu dans le fichier courant. répertoire ou depuis un sous-répertoire si ledit argument est passé dans $ 1

#!/bin/bash

if [ -z "$1" ] ; then

# loop in current dir
ls | while read line; do
  ecriv=`pwd`"/"$line
if [ -f $ecriv ] ; then
    md5sum "$ecriv"
Elif [ -d $ecriv ] ; then
    sh myScript "$line" # call this script again
fi

done


else # if a directory is specified in argument $1

ls "$1" | while read line; do
  ecriv=`pwd`"/$1/"$line

if [ -f $ecriv ] ; then
    md5sum "$ecriv"

Elif [ -d $ecriv ] ; then
    sh myScript "$line"
fi

done


fi
1
alan

Si vous voulez vraiment être indépendant des attributs du système de fichiers et des différences de niveau binaire de certaines versions de tar, vous pouvez utiliser cpio:

cpio -i -e theDirname | md5sum
1
peterh

Il y a deux autres solutions:

Créer:

du -csxb /path | md5sum > file

ls -alR -I dev -I run -I sys -I tmp -I proc /path | md5sum > /tmp/file

Vérifier:

du -csxb /path | md5sum -c file

ls -alR -I dev -I run -I sys -I tmp -I proc /path | md5sum -c /tmp/file
0
Nick

md5sum a bien fonctionné pour moi, mais j'ai eu des problèmes avec sort et le tri des noms de fichiers. Donc, au lieu de cela, j'ai trié par résultat md5sum. J'avais également besoin d'exclure certains fichiers afin de créer des résultats comparables.

find . -type f -print0 \ | xargs -r0 md5sum \ | grep -v ".env" \ | grep -v "vendor/autoload.php" \ | grep -v "vendor/composer/" \ | sort -d \ | md5sum

0
MonkeyMonkey