Wie kann ich eine MD5-Prüfsumme eines Verzeichnisses berechnen?


133

Ich muss eine zusammenfassende MD5-Prüfsumme für alle Dateien eines bestimmten Typs ( *.pyzum Beispiel) berechnen, die sich unter einem Verzeichnis und allen Unterverzeichnissen befinden.

Was ist der beste Weg das zu tun?

Bearbeiten: Die vorgeschlagenen Lösungen sind sehr schön, aber das ist nicht genau das, was ich brauche. Ich suche nach einer Lösung, um eine einzige zusammenfassende Prüfsumme zu erhalten, die das Verzeichnis als Ganzes eindeutig identifiziert - einschließlich des Inhalts aller seiner Unterverzeichnisse.


Schauen Sie sich dies und das an, um eine detailliertere Erklärung zu erhalten.
luvieere

3
Scheint mir eine Superuser-Frage zu sein.
Noldorin

8
Beachten Sie, dass Prüfsummen nichts eindeutig identifizieren.
Hosam Aly

1
Warum sollten Sie zwei Verzeichnisbäume haben, die möglicherweise "gleich" sind oder nicht und die Sie eindeutig identifizieren möchten? Ist die Zeit zum Erstellen / Ändern / Zugreifen auf Dateien wichtig? Ist die Versionskontrolle das, was Sie wirklich brauchen?
jmucchiello

Was in meinem Fall wirklich wichtig ist, ist die Ähnlichkeit des gesamten Verzeichnisbauminhalts, was AFAIK Folgendes bedeutet: 1) Der Inhalt einer Datei unter dem Verzeichnisbaum wurde nicht geändert. 2) Dem Verzeichnisbaum wurde keine neue Datei hinzugefügt. 3) Keine Datei wurde gelöscht
victorz

Antworten:


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

Der Befehl find listet alle Dateien auf, die mit .py enden. Die md5sum wird für jede .py-Datei berechnet. awk wird verwendet, um die md5sums auszuwählen (wobei die Dateinamen ignoriert werden, die möglicherweise nicht eindeutig sind). Die md5-Summen sind sortiert. Die md5sum dieser sortierten Liste wird dann zurückgegeben.

Ich habe dies getestet, indem ich ein Testverzeichnis kopiert habe:

rsync -a ~/pybin/ ~/pybin2/

Ich habe einige der Dateien in ~ / pybin2 umbenannt.

Der find...md5sumBefehl gibt für beide Verzeichnisse dieselbe Ausgabe zurück.

2bcf49a4d19ef9abd284311108d626f1  -

24
Beachten Sie, dass dieselbe Prüfsumme generiert wird, wenn eine Datei umbenannt wird. Dies passt also nicht wirklich zu einer "Prüfsumme, die das Verzeichnis als Ganzes eindeutig identifiziert", wenn Sie das Dateilayout als Teil der Signatur betrachten.
Valentin Milea

1
Sie können die Befehlszeile leicht ändern, um jeder Dateiprüfsumme den Namen der Datei (oder noch besser den relativen Pfad der Datei von / path / nach / dir /) voranzustellen, damit er in der endgültigen Prüfsumme berücksichtigt wird.
Michael Zilbermann

4
@ zim2001: Ja, es könnte geändert werden, aber da ich das Problem verstanden habe (insbesondere aufgrund des Kommentars des OP unter der Frage), wollte das OP, dass zwei Verzeichnisse als gleich angesehen werden, wenn der Inhalt der Dateien unabhängig vom Dateinamen oder identisch ist sogar relativer Pfad.
Unutbu

@unutbu: Ich weiß; Ich reagierte auf die vorherige Notiz von Valentin Milea.
Michael Zilbermann

@ValentinMilea Entfernen Sie einfach das awk ...Teil, wenn Sie das Layout als Teil der Signatur betrachten.
Segfault

166

Erstellen Sie im Handumdrehen eine Teerarchivdatei und leiten Sie diese an md5sum:

tar c dir | md5sum

Dies erzeugt eine einzelne MD5-Summe, die für Ihre Datei- und Unterverzeichnis-Einrichtung eindeutig sein sollte. Es werden keine Dateien auf der Festplatte erstellt.


25
@CharlesB mit einer einzigen Prüfsumme weiß man nie, welche Datei anders ist. Die Frage betraf eine einzelne Prüfsumme für ein Verzeichnis.
Hawken

17
ls -alR dir | md5sum. Dies ist noch besser keine Komprimierung nur ein Lesen. Es ist einzigartig, weil der Inhalt die Mod-Zeit und Größe der Datei enthält;)
Sid

14
@ Daps0l - Mein Befehl enthält keine Komprimierung. Sie müssen zfür gzip oder jfür bzip2 hinzufügen . Ich habe beides nicht getan.
ire_and_curses

7
Achten Sie darauf, dass dadurch der Zeitstempel der Dateien und anderer Elemente in die Prüfsummenberechnung integriert wird, nicht nur der Inhalt der Dateien
Michael Zilbermann,

10
Das ist süß, aber es funktioniert nicht wirklich. Es gibt keine Garantie dafür, dass tarder gleiche Satz von Dateien zweimal oder auf zwei verschiedenen Computern genau das gleiche Ergebnis liefert.
Fletom

46

Der Vorschlag von ire_and_curses zur Verwendung tar c <dir>weist einige Probleme auf:

  • tar verarbeitet Verzeichniseinträge in der Reihenfolge, in der sie im Dateisystem gespeichert sind, und es gibt keine Möglichkeit, diese Reihenfolge zu ändern. Dies kann effektiv zu völlig unterschiedlichen Ergebnissen führen, wenn Sie das "gleiche" Verzeichnis an verschiedenen Stellen haben, und ich kenne keine Möglichkeit, dies zu beheben (tar kann seine Eingabedateien nicht in einer bestimmten Reihenfolge "sortieren").
  • Normalerweise ist es mir wichtig, ob Gruppen- und Eigentümer-ID-Nummern identisch sind, nicht unbedingt, ob die Zeichenfolgendarstellung von Gruppe / Eigentümer identisch ist. Dies entspricht beispielsweise dem, was es rsync -a --deletetut: Es synchronisiert praktisch alles (minus xattrs und acls), synchronisiert jedoch Eigentümer und Gruppe basierend auf ihrer ID und nicht anhand der Zeichenfolgendarstellung. Wenn Sie also mit einem anderen System synchronisiert haben, das nicht unbedingt dieselben Benutzer / Gruppen hat, sollten Sie --numeric-ownertar das Flag hinzufügen
  • tar enthält den Dateinamen des Verzeichnisses, das Sie selbst überprüfen, nur etwas, das Sie beachten sollten.

Solange es keine Lösung für das erste Problem gibt (oder wenn Sie nicht sicher sind, dass es Sie nicht betrifft), würde ich diesen Ansatz nicht verwenden.

Die findoben vorgeschlagenen basierten Lösungen sind auch nicht gut, da sie nur Dateien und keine Verzeichnisse enthalten. Dies wird zu einem Problem, wenn Sie bei der Prüfsumme leere Verzeichnisse berücksichtigen sollten.

Schließlich werden die meisten Lösungsvorschläge nicht konsistent sortiert, da die Sortierung systemübergreifend unterschiedlich sein kann.

Dies ist die Lösung, die ich mir ausgedacht habe:

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

Hinweise zu dieser Lösung:

  • Dies LC_ALL=Csoll eine zuverlässige Sortierreihenfolge zwischen den Systemen gewährleisten
  • Dies unterscheidet nicht zwischen einem Verzeichnis "named \ nwithanewline" und zwei Verzeichnissen "named" und "withanewline", aber die Wahrscheinlichkeit, dass dies auftritt, scheint sehr unwahrscheinlich. Normalerweise behebt man dies mit einem -print0Flag für, findaber da hier andere Dinge vor sich gehen, kann ich nur Lösungen sehen, die den Befehl komplizierter machen würden, als es sich lohnt.

PS: Eines meiner Systeme verwendet eine begrenzte Busybox, finddie weder unterstützt -execnoch -print0markiert. Außerdem wird '/' angehängt, um Verzeichnisse zu kennzeichnen, während findutils find dies nicht zu tun scheint. Daher muss ich für diesen Computer Folgendes ausführen:

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

Glücklicherweise habe ich keine Dateien / Verzeichnisse mit Zeilenumbrüchen im Namen, daher ist dies auf diesem System kein Problem.


1
+1: Sehr interessant! Wollen Sie damit sagen, dass die Reihenfolge zwischen verschiedenen Dateisystemtypen oder innerhalb desselben Dateisystems unterschiedlich sein kann?
ire_and_curses

2
beide. Es hängt nur von der Reihenfolge der Verzeichniseinträge in jedem Verzeichnis ab. AFAIK-Verzeichniseinträge (im Dateisystem) werden nur in der Reihenfolge erstellt, in der Sie "Dateien im Verzeichnis erstellen". Ein einfaches Beispiel: $ mkdir a; Berühren Sie a / file-1; Berühren Sie a / file-2 $ mkdir b; Berühren Sie b / file-2; Berühren Sie b / file-1 $ (cd a; tar -c. | md5sum) fb29e7af140aeea5a2647974f7cdec77 - $ (cd b; tar -c. | md5sum) a3a39358158a87059b9f111ccffa1023 -
Dieter_be

14

Wenn Sie sich nur für Dateien und nicht für leere Verzeichnisse interessieren, funktioniert dies gut:

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

10

Der Vollständigkeit halber gibt es md5deep (1) ; Es ist aufgrund der Filteranforderung * .py nicht direkt anwendbar, sollte aber zusammen mit find (1) gut funktionieren.


Welche Parameter würde ich verwenden, wenn ich nur die md5-Prüfsumme eines Verzeichnisses berechnen wollte?
Gabriel Fair

9

Eine Lösung, die für mich am besten funktioniert hat:

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

Grund, warum es bei mir am besten funktioniert hat:

  1. Behandelt Dateinamen, die Leerzeichen enthalten
  2. Ignoriert Metadaten des Dateisystems
  3. Erkennt, ob die Datei umbenannt wurde

Probleme mit anderen Antworten:

Dateisystem-Metadaten werden nicht ignoriert für:

tar c - "$path" | md5sum

Behandelt keine Dateinamen, die Leerzeichen enthalten, und erkennt auch nicht, ob die Datei umbenannt wurde:

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

4

Wenn Sie eine MD5-Summe möchten, die sich über das gesamte Verzeichnis erstreckt, würde ich so etwas tun

cat *.py | md5sum 

1
Verwenden Sie für Unterverzeichnisse so etwas wie cat **.py| md5sum
Ramon

3

Prüfen Sie alle Dateien, einschließlich des Inhalts und ihrer Dateinamen

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

Wie oben, jedoch nur mit * .py-Dateien

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

Sie können auch Symlinks folgen, wenn Sie möchten

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

Andere Optionen, die Sie mit grep verwenden könnten

-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)


2

Technisch müssen Sie nur laufen ls -lR *.py | md5sum. Sofern Sie sich keine Sorgen darüber machen, dass jemand die Dateien ändert und sie auf ihre ursprünglichen Daten zurücksetzt und niemals die Größe der Dateien ändert, sollte die Ausgabe von lsIhnen mitteilen, ob sich die Datei geändert hat. Mein Unix-foo ist schwach, daher benötigen Sie möglicherweise weitere Befehlszeilenparameter, um die Erstellungszeit und die Änderungszeit zum Drucken zu erhalten. lsAußerdem erfahren Sie, ob sich die Berechtigungen für die Dateien geändert haben (und ich bin sicher, dass es Schalter gibt, mit denen Sie das deaktivieren können, wenn Sie sich nicht darum kümmern).


3
Dies mag für einige Anwendungsfälle geeignet sein, aber im Allgemeinen soll die Prüfsumme nur den Inhalt und nicht die Daten widerspiegeln. Wenn ich zum Beispiel toucheine Datei habe, um ihr Datum (aber nicht ihren Inhalt) zu ändern, würde ich erwarten, dass die Prüfsumme unverändert bleibt.
Todd Owen


1

Ich hatte das gleiche Problem, also habe ich mir dieses Skript ausgedacht, das nur die md5-Summen der Dateien im Verzeichnis auflistet. Wenn es ein Unterverzeichnis findet, wird es von dort aus erneut ausgeführt. Dazu muss das Skript in der Lage sein, das aktuelle Skript auszuführen Verzeichnis oder aus einem Unterverzeichnis, wenn das Argument in $ 1 übergeben wird

#!/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

Ich bin mir ziemlich sicher, dass dieses Skript fehlschlägt, wenn Dateinamen Leerzeichen oder Anführungszeichen enthalten. Ich finde das nervig mit Bash-Skripten, aber ich ändere das IFS.
localhost

1

Wenn Sie wirklich unabhängig von den Dateisystemattributen und den Unterschieden auf Bitebene einiger Tar-Versionen sein möchten, können Sie cpio verwenden:

cpio -i -e theDirname | md5sum

0

Es gibt zwei weitere Lösungen:

Erstellen:

du -csxb /path | md5sum > file

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

Prüfen:

du -csxb /path | md5sum -c file

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

0

md5sumfunktionierte gut für mich, aber ich hatte Probleme mit sortund Sortieren von Dateinamen. Also habe ich stattdessen nach md5sumErgebnis sortiert . Ich musste auch einige Dateien ausschließen, um vergleichbare Ergebnisse zu erzielen.

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

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.