Der richtige Weg hängt genau davon ab, warum Sie fragen:
Option 1: Nur Daten vergleichen
Wenn Sie nur einen Hash des Dateiinhalts des Baums benötigen, ist dies der Trick:
$ find -s somedir -type f -exec md5sum {} \; | md5sum
Dabei werden zunächst alle Dateiinhalte einzeln in vorhersehbarer Reihenfolge zusammengefasst und anschließend die Liste der zu hashenden Dateinamen und MD5-Hashes selbst übergeben. Dabei wird ein einziger Wert angegeben, der sich nur ändert, wenn sich der Inhalt einer der Dateien in der Baumstruktur ändert.
Funktioniert leider find -s
nur mit BSD find (1), verwendet unter macOS, FreeBSD, NetBSD und OpenBSD. Um auf einem System mit GNU oder SUS etwas Vergleichbares zu finden (1), benötigen Sie etwas Hässlicheres:
$ find somedir -type f -exec md5sum {} \; | sort -k 2 | md5sum
Wir haben find -s
mit einem Anruf zu ersetzt sort
. Das -k 2
Bit weist es an, den MD5-Hash zu überspringen, sodass nur die Dateinamen, die sich in Feld 2 bis zum Zeilenende befinden, nach sort
Abrechnung sortiert werden .
Diese Version des Befehls weist eine Schwachstelle auf. Dies kann zu Verwirrung führen, wenn Dateinamen mit Zeilenumbrüchen enthalten sind, da der sort
Aufruf wie mehrere Zeilen aussieht . Die find -s
Variante hat dieses Problem nicht, da das Durchlaufen und Sortieren des Baumes innerhalb desselben Programms erfolgt find
.
In beiden Fällen ist die Sortierung erforderlich, um Fehlalarme zu vermeiden: Die gängigsten Unix / Linux-Dateisysteme verwalten die Verzeichnislisten nicht in einer stabilen, vorhersehbaren Reihenfolge. Sie erkennen dies möglicherweise nicht an der Verwendung von ls
und solchen, die den Verzeichnisinhalt für Sie unbemerkt sortieren. find
without -s
oder ein sort
Aufruf druckt Dateien in der Reihenfolge aus, in der das zugrunde liegende Dateisystem sie zurückgibt. Dies führt dazu, dass dieser Befehl einen geänderten Hashwert ausgibt, wenn sich die Reihenfolge der Dateien ändert, die als Eingabe übergeben werden.
Möglicherweise müssen Sie die md5sum
Befehle in md5
oder eine andere Hash-Funktion ändern . Wenn Sie eine andere Hash-Funktion auswählen und die zweite Form des Befehls für Ihr System benötigen, müssen Sie den sort
Befehl möglicherweise entsprechend anpassen . Eine weitere Falle ist, dass einige Datensummierungsprogramme überhaupt keinen Dateinamen ausschreiben, zum Beispiel das alte Unix- sum
Programm.
Diese Methode ist etwas ineffizient und ruft md5sum
N + 1-mal auf, wobei N die Anzahl der Dateien im Baum ist. Dies ist jedoch ein notwendiger Kostenfaktor, um das Durchsuchen von Datei- und Verzeichnismetadaten zu vermeiden.
Option 2: Vergleichen Sie Daten und Metadaten
Wenn Sie feststellen müssen, dass sich in einem Baum etwas geändert hat, und nicht nur der Dateiinhalt, bitten Sie tar
darum, den Verzeichnisinhalt für Sie zu packen, und senden Sie ihn dann an md5sum
:
$ tar -cf - somedir | md5sum
Da tar
auch Dateiberechtigungen, Eigentumsrechte usw. angezeigt werden, erkennt dies auch Änderungen an diesen Dingen, nicht nur Änderungen am Dateiinhalt.
Diese Methode ist erheblich schneller, da sie nur einen Durchlauf über den Baum macht und das Hash-Programm nur einmal ausführt.
Wie bei der find
oben beschriebenen Methode tar
werden Dateinamen in der Reihenfolge verarbeitet, in der das zugrunde liegende Dateisystem sie zurückgibt. Möglicherweise können Sie in Ihrer Anwendung sicher sein, dass dies nicht der Fall ist. Ich kann mir mindestens drei verschiedene Nutzungsmuster vorstellen, bei denen dies wahrscheinlich der Fall ist. (Ich werde sie nicht auflisten, da wir uns in einem nicht näher definierten Gebiet bewegen. Jedes Dateisystem kann hier unterschiedlich sein, selbst von einer Version des Betriebssystems zur nächsten.)
Wenn Sie falsch positive Ergebnisse erhalten, würde ich empfehlen, die find | cpio
Option in Gilles 'Antwort zu wählen .
find .
stattdessen zu verwendenfind somedir
. Auf diese Weise sind die Dateinamen identisch, wenn verschiedene zu suchende Pfadangaben angegeben werden. Das kann schwierig sein :-)find somedir -type f -exec sh -c "openssl dgst -sha1 -binary {} | xxd -p" \; | sort | openssl dgst -sha1
Alle Dateinamen ignorieren (sollte mit Zeilenumbrüchen funktionieren)Die Prüfsumme muss eine deterministische und eindeutige Darstellung der Dateien als Zeichenfolge sein. Deterministisch bedeutet, dass Sie dasselbe Ergebnis erzielen, wenn Sie dieselben Dateien an denselben Speicherorten ablegen. Eindeutig bedeutet, dass zwei unterschiedliche Dateigruppen unterschiedliche Darstellungen haben.
Daten und Metadaten
Ein Archiv mit den Dateien zu erstellen ist ein guter Anfang. Dies ist eine eindeutige Darstellung (offensichtlich, da Sie die Dateien durch Extrahieren des Archivs wiederherstellen können). Es kann Dateimetadaten wie Datum und Eigentümer enthalten. Dies ist jedoch noch nicht ganz richtig: Ein Archiv ist mehrdeutig, da seine Darstellung von der Reihenfolge abhängt, in der die Dateien gespeichert werden, und gegebenenfalls von der Komprimierung.
Eine Lösung besteht darin, die Dateinamen vor dem Archivieren zu sortieren. Wenn Ihre Dateinamen keine Zeilenumbrüche enthalten, können Sie sie auflisten
find | sort
und in dieser Reihenfolge zum Archiv hinzufügen. Achten Sie darauf, dass der Archivierer nicht in Verzeichnisse zurückkehrt. Hier einige Beispiele mit POSIXpax
, GNU tar und cpio:Nur Namen und Inhalte, auf technisch einfache Weise
Wenn Sie nur die Dateidaten und keine Metadaten berücksichtigen möchten, können Sie ein Archiv erstellen, das nur den Dateiinhalt enthält, für das es jedoch keine Standardwerkzeuge gibt. Anstatt den Dateiinhalt einzuschließen, können Sie den Hash der Dateien einschließen. Wenn die Dateinamen keine Zeilenumbrüche enthalten und es nur reguläre Dateien und Verzeichnisse gibt (keine symbolischen Links oder Sonderdateien), ist dies recht einfach, aber Sie müssen sich um einige Dinge kümmern:
Wir fügen der Liste der Prüfsummen eine Verzeichnisliste hinzu, da ansonsten leere Verzeichnisse unsichtbar wären. Die Dateiliste ist sortiert (in einem bestimmten, reproduzierbaren Gebietsschema - danke an Peter.O, der mich daran erinnert hat).
echo
trennt die beiden Teile (ohne dies könnten Sie einige leere Verzeichnissemd5sum
erstellen, deren Name wie eine Ausgabe aussieht , die auch für normale Dateien durchgelassen werden könnte). Wir schließen auch eine Liste der Dateigrößen, um zu verhindern Länge Verlängerungs - Attacken .MD5 ist übrigens veraltet. Wenn es verfügbar ist, erwägen Sie die Verwendung von SHA-2 oder mindestens SHA-1.
Namen und Daten, die Zeilenumbrüche in Namen unterstützen
Hier ist eine Variante des obigen Codes, die sich auf GNU-Tools stützt, um die Dateinamen mit Null-Bytes zu trennen. Auf diese Weise können Dateinamen Zeilenumbrüche enthalten. Die GNU Digest-Dienstprogramme zitieren Sonderzeichen in ihrer Ausgabe, damit es nicht zu mehrdeutigen Zeilenumbrüchen kommt.
Ein robusterer Ansatz
Hier ist ein minimal getestetes Python-Skript, das einen Hash erstellt, der eine Hierarchie von Dateien beschreibt. Es berücksichtigt Verzeichnisse und Dateiinhalte, ignoriert symbolische Links und andere Dateien und gibt einen schwerwiegenden Fehler zurück, wenn eine Datei nicht gelesen werden kann.
quelle
LC_ALL=C sort
für die Überprüfung aus verschiedenen Umgebungen ... (+ 1 BTW)LC_ALL=C
ist wichtig, wenn Sie auf mehreren Computern und Betriebssystemen ausgeführt werden.cpio -o -
bedeutet Verwendet cpio nicht standardmäßig stdin / out? GNU cpio 2.12 produziertcpio: Too many arguments
Schauen Sie sich md5deep an . Einige der Funktionen von md5deep, die Sie interessieren könnten:
quelle
.../foo: Is a directory
, was gibt es?md5deep -r -l -j0 . | md5sum
(wobei-r
rekursiv ist,-l
bedeutet "relative Pfade verwenden", damit der absolute Pfad der Dateien nicht stört, wenn versucht wird, den Inhalt von zwei Verzeichnissen zu vergleichen, und-j0
bedeutet, dass 1 Thread verwendet wird, um Nichtdeterminismus aufgrund von Nichtdeterminismus zu verhindern zu einzelnen md5sums, die in verschiedenen Aufträgen zurückgegeben werden).Wenn Sie lediglich die Unterschiede zwischen zwei Verzeichnissen ermitteln möchten, sollten Sie die Verwendung von diff in Betracht ziehen.
Versuche dies:
quelle
Sie können jede Datei rekursiv hashen und dann den resultierenden Text hashen:
md5deep ist erforderlich.
quelle
md5deep
Verwendunghashdeep
auf Ubuntu 16.04 weil md5deep Paket ist nur ein Übergang-Dummy für hashdeep.## Invoked from: /home/myuser/dev/
des aktuellen Pfads und## $ hashdeep -s -r -l ~/folder/
. Dies muss sortiert werden, sodass der letzte Hash anders ist, wenn Sie Ihren aktuellen Ordner oder Ihre aktuelle Befehlszeile ändern.Dateiinhalte nur , ohne Dateinamen
Ich brauchte eine Version, die nur die Dateinamen überprüfte, weil sich der Inhalt in verschiedenen Verzeichnissen befand.
Diese Version (Warren Youngs Antwort) hat sehr geholfen, aber meine Version
md5sum
gibt den Dateinamen (relativ zu dem Pfad, von dem aus ich den Befehl ausgeführt habe) aus, und die Ordnernamen waren unterschiedlich. Obwohl die einzelnen Dateiprüfsummen übereinstimmten, stimmte die endgültige Prüfsumme nicht überein nicht.Um dies zu beheben, musste ich in meinem Fall nur den Dateinamen in jeder Zeile der
find
Ausgabe entfernen (wählen Sie nur das erste Wort aus, das durch Leerzeichen getrennt istcut
):quelle
lösung :
funktioniert schnell und einfacher als bash scripting.
Siehe doc: https://pypi.python.org/pypi/checksumdir/1.0.5
quelle
nix-hash
vom Nix Paketmanagerquelle
Ich benutze dieses Snippet für moderate Volumes :
find . -xdev -type f -print0 | LC_COLLATE=C sort -z | xargs -0 cat | md5sum -
und dieses für XXXL :
find . -xdev -type f -print0 | LC_COLLATE=C sort -z | xargs -0 tail -qc100 | md5sum -
quelle
-xdev
Flagge?man find
-xdev Don't descend directories on other filesystems.
Eine gute Baumprüfsumme ist die Baum-ID von Git.
Es gibt leider kein eigenständiges Tool, das das kann (zumindest weiß ich es nicht), aber wenn Sie Git zur Hand haben, können Sie einfach so tun, als würden Sie ein neues Repository einrichten und die zu überprüfenden Dateien zum Index hinzufügen.
Auf diese Weise können Sie den (reproduzierbaren) Baum-Hash erzeugen, der nur Inhalt, Dateinamen und einige reduzierte Dateimodi (ausführbar) enthält.
quelle
Wenn Sie die Berechnung der Prüfsumme für ein großes Verzeichnis beschleunigen möchten, versuchen Sie als Reaktion auf diese hervorragende Antwort GNU Parallel :
(Dies verwendet einen Mac mit
md5
, bei Bedarf ersetzen.)Das
-k
Flag ist wichtig,parallel
um die Reihenfolge aufrechtzuerhalten. Andernfalls kann sich die Gesamtsumme ändern, auch wenn alle Dateien gleich sind.-n 100
Wenn Sie jede Instanz vonmd5
mit 100 Argumenten ausführen möchten, können Sie diesen Parameter für eine optimale Laufzeit optimieren. Siehe auch-X
flag ofparallel
(obwohl in meinem persönlichen Fall das einen Fehler verursacht hat.)quelle
Ein Skript , das gut getestet und unterstützt eine Reihe von Operationen , einschließlich Duplikate zu finden, tun Vergleiche sowohl auf Daten und Metadaten, Ergänzungen sowie Änderungen und Löschungen zeigen, könnten Sie Fingerabdruck .
Fingerprint erzeugt derzeit keine einzige Prüfsumme für ein Verzeichnis, sondern eine Transkriptionsdatei, die Prüfsummen für alle Dateien in diesem Verzeichnis enthält.
Dies wird
index.fingerprint
im aktuellen Verzeichnis generiert, das Prüfsummen, Dateinamen und Dateigrößen enthält. Standardmäßig werden sowohlMD5
als auch verwendetSHA1.256
.Ich hoffe, dass ich in Zukunft die Unterstützung für Merkle Trees in Fingerprint aufnehmen kann, wodurch Sie eine einzige Prüfsumme auf oberster Ebene erhalten. Im Moment müssen Sie diese Datei für die Überprüfung aufbewahren.
quelle
Ich wollte keine neuen ausführbaren Dateien oder schwerfälligen Lösungen.
quelle
Ein robuster und sauberer Ansatz
Dies ist, was ich auf dem Kopf habe, jeder, der einige Zeit damit verbracht hat, praktisch daran zu arbeiten, hätte andere Fallstricke und Eckfälle erwischt.
Hier ist ein Werkzeug (Disclaimer: Ich bin ein Mitwirkender zu ihm) dtreetrawl , sehr leicht auf das Gedächtnis, die den meisten Fällen befasst, könnte ein wenig rau um die Ränder aber war sehr hilfreich.
Ein Beispiel für eine menschenfreundliche Ausgabe:
quelle
Individuell für alle Dateien in jedem Verzeichnis.
quelle
Die Migration zum POSIX-Archivformat wirkt sich auf GNU Tar-basierte Prüfsummen aus
Diese Antwort soll eine zusätzliche Aktualisierung des Ansatzes der Verwendung der Tar-Ausgabe zum Hashing des Inhalts von Verzeichnissen sein, wie dies (unter anderem) in den hervorragenden Antworten von Warren Young und Gilles vor einiger Zeit vorgeschlagen wurde.
Seitdem hat zumindest openSUSE (seit Release 12.2) sein Standard-GNU-Tar-Format von "GNU-Tar 1.13.x-Format" auf das (leicht) überlegene "POSIX 1003.1-2001 (pax) -Format" geändert . Ebenfalls vorgelagert (unter den Entwicklern von GNU Tar) diskutieren sie, die gleiche Migration durchzuführen, siehe zum Beispiel den letzten Absatz auf dieser Seite des GNU Tar-Handbuchs :
(Diese Seite gibt auch einen guten Überblick über die verschiedenen Archivformate, die mit GNU Tar verfügbar sind.)
In unserem Fall, in dem wir den Verzeichnisinhalt tarieren und das Ergebnis hashen, und ohne besondere Maßnahmen zu ergreifen, hat ein Wechsel vom GNU- zum POSIX-Format die folgenden Konsequenzen:
Trotz identischer Verzeichnisinhalte ist die resultierende Prüfsumme unterschiedlich.
Trotz identischer Verzeichnisinhalte unterscheidet sich die resultierende Prüfsumme von Ausführung zu Ausführung, wenn die Standard-Pax-Header verwendet werden.
Letzteres beruht auf der Tatsache, dass das POSIX-Format (pax) erweiterte pax-Header enthält, die durch eine Formatzeichenfolge bestimmt werden, die standardmäßig
%d/PaxHeaders.%p/%f
in GNU Tar verwendet wird. In dieser Zeichenfolge wird der Bezeichner%p
durch die Prozess-ID des generierenden Tar-Prozesses ersetzt, die sich natürlich von Lauf zu Lauf unterscheidet. Siehe diesen Abschnitt des GNU Tar Handbuch und insbesondere dieses für weitere Einzelheiten.Gerade jetzt aus dem Jahr 2019.3.28, gibt es eine Festschreibung akzeptiert Upstream , dass dieses Problem entschärft.
Um GNU Tar im gegebenen Anwendungsfall weiterhin verwenden zu können, kann ich die folgenden alternativen Optionen empfehlen:
Verwenden Sie die Option Tar
--format=gnu
, um Tar explizit anzuweisen, das Archiv im "alten" Format zu generieren. Dies ist obligatorisch, um "alte" Prüfsummen zu validieren.Verwenden Sie das neuere POSIX-Format, geben Sie jedoch explizit einen geeigneten Pax-Header an, z. B. durch
--pax-option="exthdr.name=%d/PaxHeaders/%f"
. Dies beeinträchtigt jedoch die Abwärtskompatibilität zu "alten" Prüfsummen.Hier ist ein Bash-Codefragment, das ich regelmäßig verwende, um Prüfsummen von Verzeichnisinhalten einschließlich Metadaten zu berechnen:
Hier
<paths>
wird durch eine durch Leerzeichen getrennte Liste der Pfade aller Verzeichnisse ersetzt, die von der Prüfsumme abgedeckt werden sollen. Der Zweck der Verwendung des Gebietsschemas C, der Null-Byte-Trennung von Dateinamen und der Verwendung von find und sort, um eine dateisystemunabhängige Reihenfolge der Dateien im Archiv zu erhalten, wird bereits in anderen Antworten ausreichend erörtert.Die umgebenden Klammern halten die
LC_ALL
Einstellung lokal in einer Unterschale.Außerdem verwende ich den Ausdruck
! -type s
mitfind
, um Warnungen von Tar zu vermeiden, die auftreten, wenn Socket-Dateien Teil des Verzeichnisinhalts sind: GNU Tar archiviert Sockets nicht. Wenn Sie über übersprungene Sockets benachrichtigt werden möchten, lassen Sie diesen Ausdruck weg.Ich benutze
--numeric-owner
mit Tar, um später die Prüfsummen auch auf Systemen überprüfen zu können, bei denen nicht alle Dateibesitzer bekannt sind.Die
--atime-preserve
Option für Tar wird besser weggelassen, wenn eine der Optionen<paths>
auf einem schreibgeschützten Gerät liegt. Andernfalls werden Sie für jede einzelne Datei gewarnt, deren Zugriffszeitstempel Tar nicht wiederherstellen konnte. Bei aktivierter Schreibfunktion verwende<paths>
ich diese Option, um die Zugriffszeitstempel in den Hash-Verzeichnissen beizubehalten.Die Tar-Option
--no-recursion
, die bereits in Gilles 'Vorschlag verwendet wurde , verhindert, dass Tar rekursiv in Verzeichnisse herunterfährt und stattdessen Datei für Datei mit dem arbeitet, was von der sortiertenfind
Ausgabe zugeführt wird.Und schließlich ist es nicht wahr, dass ich benutze
md5sum
: Ich benutze tatsächlichsha256sum
.quelle
Wenn Sie md5 nicht benötigen, können Sie es versuchen
quelle