Wie erhalte ich die MD5-Summe des Inhalts eines Verzeichnisses als eine Summe?


171

Das Programm md5sum bietet keine Prüfsummen für Verzeichnisse. Ich möchte eine einzelne MD5-Prüfsumme für den gesamten Inhalt eines Verzeichnisses erhalten, einschließlich Dateien in Unterverzeichnissen. Das heißt, eine kombinierte Prüfsumme, die aus allen Dateien besteht. Gibt es eine Möglichkeit, dies zu tun?

Antworten:


186

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 -snur 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 -smit einem Anruf zu ersetzt sort. Das -k 2Bit weist es an, den MD5-Hash zu überspringen, sodass nur die Dateinamen, die sich in Feld 2 bis zum Zeilenende befinden, nach sortAbrechnung 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 sortAufruf wie mehrere Zeilen aussieht . Die find -sVariante 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 lsund solchen, die den Verzeichnisinhalt für Sie unbemerkt sortieren. findwithout -soder ein sortAufruf 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 md5sumBefehle in md5oder 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 sortBefehl möglicherweise entsprechend anpassen . Eine weitere Falle ist, dass einige Datensummierungsprogramme überhaupt keinen Dateinamen ausschreiben, zum Beispiel das alte Unix- sumProgramm.

Diese Methode ist etwas ineffizient und ruft md5sumN + 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 tardarum, den Verzeichnisinhalt für Sie zu packen, und senden Sie ihn dann an md5sum:

$ tar -cf - somedir | md5sum

Da tarauch 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 findoben beschriebenen Methode tarwerden 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 | cpioOption in Gilles 'Antwort zu wählen .


7
Ich denke, es ist am besten, zu dem Verzeichnis zu navigieren, das verglichen wird, und find .stattdessen zu verwenden find somedir. Auf diese Weise sind die Dateinamen identisch, wenn verschiedene zu suchende Pfadangaben angegeben werden. Das kann schwierig sein :-)
Abbafei

Sollen wir die Dateien auch sortieren?
CMCDragonkai

@ CMCDragonkai: Was meinst du? Im ersten Fall, wir haben die Liste der Dateinamen sortieren. Im zweiten Fall, tun wir bewusst nicht , weil ein Teil der betonte , alles im ersten Satz ist , dass die Reihenfolge der Dateien in einem Verzeichnis hat sich geändert, so dass Sie nichts sortieren möchten.
Warren Young

@WarrenYoung Können Sie etwas genauer erklären, warum Option 2 nicht immer besser ist? Es scheint schneller, einfacher und plattformübergreifender zu sein. In welchem ​​Fall sollte es nicht Option 1 sein?
Robin Winslow

Alternative 1: find somedir -type f -exec sh -c "openssl dgst -sha1 -binary {} | xxd -p" \; | sort | openssl dgst -sha1Alle Dateinamen ignorieren (sollte mit Zeilenumbrüchen funktionieren)
windm

38

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 | sortund in dieser Reihenfolge zum Archiv hinzufügen. Achten Sie darauf, dass der Archivierer nicht in Verzeichnisse zurückkehrt. Hier einige Beispiele mit POSIX pax, GNU tar und cpio:

find | LC_ALL=C sort | pax -w -d | md5sum
find | LC_ALL=C sort | tar -cf - -T - --no-recursion | md5sum
find | LC_ALL=C sort | cpio -o | md5sum

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:

{ export LC_ALL=C;
  find -type f -exec wc -c {} \; | sort; echo;
  find -type f -exec md5sum {} + | sort; echo;
  find . -type d | sort; find . -type d | sort | md5sum;
} | md5sum

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). echotrennt die beiden Teile (ohne dies könnten Sie einige leere Verzeichnisse md5sumerstellen, 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.

{ export LC_ALL=C;
  du -0ab | sort -z; # file lengths, including directories (with length 0)
  echo | tr '\n' '\000'; # separator
  find -type f -exec sha256sum {} + | sort -z; # file hashes
  echo | tr '\n' '\000'; # separator
  echo "End of hashed data."; # End of input marker
} | sha256sum

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.

#! /usr/bin/env python
import hashlib, hmac, os, stat, sys
## Return the hash of the contents of the specified file, as a hex string
def file_hash(name):
    f = open(name)
    h = hashlib.sha256()
    while True:
        buf = f.read(16384)
        if len(buf) == 0: break
        h.update(buf)
    f.close()
    return h.hexdigest()
## Traverse the specified path and update the hash with a description of its
## name and contents
def traverse(h, path):
    rs = os.lstat(path)
    quoted_name = repr(path)
    if stat.S_ISDIR(rs.st_mode):
        h.update('dir ' + quoted_name + '\n')
        for entry in sorted(os.listdir(path)):
            traverse(h, os.path.join(path, entry))
    elif stat.S_ISREG(rs.st_mode):
        h.update('reg ' + quoted_name + ' ')
        h.update(str(rs.st_size) + ' ')
        h.update(file_hash(path) + '\n')
    else: pass # silently symlinks and other special files
h = hashlib.sha256()
for root in sys.argv[1:]: traverse(h, root)
h.update('end\n')
print h.hexdigest()

OK, das funktioniert, danke. Aber gibt es eine Möglichkeit, ohne Metadaten zu tun? Im Moment brauche ich es nur für den eigentlichen Inhalt.

Wie wäre es LC_ALL=C sortfür die Überprüfung aus verschiedenen Umgebungen ... (+ 1 BTW)
Peter.O

Sie haben dafür ein ganzes Python-Programm erstellt? Vielen Dank! Das ist wirklich mehr als ich erwartet hatte. :-) Wie auch immer, ich werde diese Methoden sowie die neue Option 1 von Warren überprüfen.

Gute Antwort. Das Festlegen der Sortierreihenfolge mit LC_ALL=Cist wichtig, wenn Sie auf mehreren Computern und Betriebssystemen ausgeführt werden.
Davor Cubranic

Was cpio -o -bedeutet Verwendet cpio nicht standardmäßig stdin / out? GNU cpio 2.12 produziertcpio: Too many arguments
Jan Tojnar

12

Schauen Sie sich md5deep an . Einige der Funktionen von md5deep, die Sie interessieren könnten:

Rekursive Operation - md5deep kann einen gesamten Verzeichnisbaum rekursiv untersuchen. Das heißt, berechnen Sie das MD5 für jede Datei in einem Verzeichnis und für jede Datei in jedem Unterverzeichnis.

Vergleichsmodus - md5deep akzeptiert eine Liste bekannter Hashes und vergleicht diese mit einer Reihe von Eingabedateien. Das Programm kann entweder die Eingabedateien anzeigen, die mit der Liste der bekannten Hashes übereinstimmen, oder die, die nicht übereinstimmen.

...


Schön, aber ich kann es nicht zum Laufen bringen, heißt es .../foo: Is a directory, was gibt es?
Camilo Martin

3
Md5deep alleine löst das OP-Problem nicht, da es keine konsolidierte md5sum druckt, sondern nur die md5sum für jede Datei im Verzeichnis. Das heißt, Sie können md5sum die Ausgabe von md5deep - nicht ganz das, was das OP wollte, aber ist in der Nähe! ZB für das aktuelle Verzeichnis: md5deep -r -l -j0 . | md5sum(wobei -rrekursiv ist, -lbedeutet "relative Pfade verwenden", damit der absolute Pfad der Dateien nicht stört, wenn versucht wird, den Inhalt von zwei Verzeichnissen zu vergleichen, und -j0bedeutet, dass 1 Thread verwendet wird, um Nichtdeterminismus aufgrund von Nichtdeterminismus zu verhindern zu einzelnen md5sums, die in verschiedenen Aufträgen zurückgegeben werden).
Stevie

Wie ignoriere ich einige Dateien / Verzeichnisse im Pfad?
Sandeepan Nath

9

Wenn Sie lediglich die Unterschiede zwischen zwei Verzeichnissen ermitteln möchten, sollten Sie die Verwendung von diff in Betracht ziehen.

Versuche dies:

diff -qr dir1 dir2

Ja, das ist auch nützlich. Ich denke, Sie meinten dir1 dir2 in diesem Befehl.

1
Normalerweise benutze ich GUIs nicht, wenn ich sie vermeiden kann, aber für Verzeichnisdifferenzen ist kdiff3 großartig und funktioniert auch auf vielen Plattformen.
Sinelaw

Mit diesem Befehl werden auch unterschiedliche Dateien gemeldet.
Serge Stroobandt

7

Sie können jede Datei rekursiv hashen und dann den resultierenden Text hashen:

> md5deep -r -l . | sort | md5sum
d43417958e47758c6405b5098f151074 *-

md5deep ist erforderlich.


1
statt md5deepVerwendung hashdeepauf Ubuntu 16.04 weil md5deep Paket ist nur ein Übergang-Dummy für hashdeep.
Palik

1
Ich habe es mit Haschisch versucht. Es werden nicht nur Hashes ausgegeben, sondern auch einige Header, einschließlich ## 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.
Truf

3

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 md5sumgibt 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 findAusgabe entfernen (wählen Sie nur das erste Wort aus, das durch Leerzeichen getrennt ist cut):

find -s somedir -type f -exec md5sum {} \; | cut -d" " -f1 | md5sum

Möglicherweise müssen Sie auch die Prüfsummen sortieren, um eine reproduzierbare Liste zu erhalten.
Eckes

3

lösung :

$ pip install checksumdir
$ checksumdir -a md5 assets/js
981ac0bc890de594a9f2f40e00f13872
$ checksumdir -a sha1 assets/js
88cd20f115e31a1e1ae381f7291d0c8cd3b92fad

funktioniert schnell und einfacher als bash scripting.

Siehe doc: https://pypi.python.org/pypi/checksumdir/1.0.5


wenn du kein pip hast, musst du es möglicherweise mit yum -y install python-pip (oder dnf / apt-get)
installieren

3

nix-hashvom Nix Paketmanager

Der Befehl nix-hash berechnet den kryptografischen Hash des Inhalts jedes Pfads und druckt ihn auf der Standardausgabe aus. Standardmäßig wird ein MD5-Hash berechnet, es stehen jedoch auch andere Hash-Algorithmen zur Verfügung. Der Hash wird hexadezimal ausgegeben.

Der Hash wird über eine Serialisierung jedes Pfads berechnet: ein Speicherauszug des Dateisystembaums, der im Pfad verwurzelt ist. Auf diese Weise können Verzeichnisse und Symlinks sowie normale Dateien gehasht werden. Der Speicherauszug ist im NAR-Format, das von nix-store --dump erstellt wurde. Nix-hash path liefert also denselben kryptografischen Hash wie nix-store --dump path | md5sum.


2

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 -


Was macht die -xdevFlagge?
Czerasz

Sie müssen man find
Folgendes eingeben

Guter Punkt :-). -xdev Don't descend directories on other filesystems.
Czerasz

1
Beachten Sie, dass dabei neue, leere Dateien ignoriert werden (wie wenn Sie eine Datei berühren).
RonJohn

Es gibt viele Fälle, in denen dies dieselbe MD5-Summe mit einer völlig anderen Datei- und Verzeichnisstruktur ergibt. Das Umbenennen von Dateien und Verzeichnissen ändert dies überhaupt nicht, wenn die Sortierreihenfolge der Dateien nicht geändert wird. Daher würde ich diesen Ansatz nicht empfehlen.
Hans-Peter Störr

2

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.


2

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 :

find -s somedir -type f | parallel -k -n 100 md5 {} | md5

(Dies verwendet einen Mac mit md5, bei Bedarf ersetzen.)

Das -kFlag ist wichtig, parallelum die Reihenfolge aufrechtzuerhalten. Andernfalls kann sich die Gesamtsumme ändern, auch wenn alle Dateien gleich sind. -n 100Wenn Sie jede Instanz von md5mit 100 Argumenten ausführen möchten, können Sie diesen Parameter für eine optimale Laufzeit optimieren. Siehe auch -Xflag of parallel(obwohl in meinem persönlichen Fall das einen Fehler verursacht hat.)


1

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.

fingerprint analyze

Dies wird index.fingerprintim aktuellen Verzeichnis generiert, das Prüfsummen, Dateinamen und Dateigrößen enthält. Standardmäßig werden sowohl MD5als auch verwendet SHA1.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.


1

Ich wollte keine neuen ausführbaren Dateien oder schwerfälligen Lösungen.

#!/bin/sh
# md5dir.sh by Camilo Martin, 2014-10-01.
# Give this a parameter and it will calculate an md5 of the directory's contents.
# It only takes into account file contents and paths relative to the directory's root.
# This means that two dirs with different names and locations can hash equally.

if [[ ! -d "$1" ]]; then
    echo "Usage: md5dir.sh <dir_name>"
    exit
fi

d="$(tr '\\' / <<< "$1" | tr -s / | sed 's-/$--')"
c=$((${#d} + 35))
find "$d" -type f -exec md5sum {} \; | cut -c 1-33,$c- | sort | md5sum | cut -c 1-32

0

Ein robuster und sauberer Ansatz

  • Das Wichtigste zuerst, belasten Sie nicht den verfügbaren Speicher ! Hash eine Datei in Stücken, anstatt die gesamte Datei zu füttern.
  • Unterschiedliche Ansätze für unterschiedliche Bedürfnisse / Zwecke (alle unten aufgeführten oder die zutreffenden auswählen):
    • Hash nur den Eintragsnamen aller Einträge im Verzeichnisbaum
    • Hash den Dateiinhalt aller Einträge (unter Beibehaltung von Meta wie Inode-Nummer, C-Zeit, Atime, M-Zeit, Größe usw., erhalten Sie die Idee)
    • Bei einem symbolischen Link ist sein Inhalt der Referenzname. Hash es oder wählen Sie zu überspringen
    • Folgen Sie dem Symlink, oder folgen Sie ihm nicht (aufgelöster Name), während Sie den Inhalt des Eintrags hashen
    • Wenn es sich um ein Verzeichnis handelt, handelt es sich bei seinem Inhalt nur um Verzeichniseinträge. Beim rekursiven Durchlaufen werden sie schließlich gehasht. Sollten die Verzeichniseintragsnamen dieser Ebene gehasht werden, um dieses Verzeichnis zu kennzeichnen? Hilfreich in Anwendungsfällen, in denen der Hash benötigt wird, um eine Änderung schnell zu identifizieren, ohne tief in den Inhalt hineingehen zu müssen. Ein Beispiel wäre, dass sich der Name einer Datei ändert, der Rest des Inhalts jedoch gleich bleibt und es sich bei allen um relativ große Dateien handelt
    • Behandeln Sie große Dateien gut (auch hier ist der Arbeitsspeicher zu beachten)
    • Behandle sehr tiefe Verzeichnisbäume (beachte die offenen Dateideskriptoren)
    • Behandeln Sie nicht standardmäßige Dateinamen
    • Wie gehe ich mit Dateien vor, die Sockets, Pipes / FIFOs, Blockgeräte und Char-Geräte sind? Müssen sie auch gehackt werden?
    • Aktualisieren Sie nicht die Zugriffszeit eines Eintrags während des Durchlaufs, da dies für bestimmte Anwendungsfälle ein Nebeneffekt und kontraproduktiv (intuitiv?) Ist.

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.

Usage:
  dtreetrawl [OPTION...] "/trawl/me" [path2,...]

Help Options:
  -h, --help                Show help options

Application Options:
  -t, --terse               Produce a terse output; parsable.
  -d, --delim=:             Character or string delimiter/separator for terse output(default ':')
  -l, --max-level=N         Do not traverse tree beyond N level(s)
  --hash                    Hash the files to produce checksums(default is MD5).
  -c, --checksum=md5        Valid hashing algorithms: md5, sha1, sha256, sha512.
  -s, --hash-symlink        Include symbolic links' referent name while calculating the root checksum
  -R, --only-root-hash      Output only the root hash. Blank line if --hash is not set
  -N, --no-name-hash        Exclude path name while calculating the root checksum
  -F, --no-content-hash     Do not hash the contents of the file

Ein Beispiel für eine menschenfreundliche Ausgabe:

...
... //clipped
...
/home/lab/linux-4.14-rc8/CREDITS
        Base name                    : CREDITS
        Level                        : 1
        Type                         : regular file
        Referent name                :
        File size                    : 98443 bytes
        I-node number                : 290850
        No. directory entries        : 0
        Permission (octal)           : 0644
        Link count                   : 1
        Ownership                    : UID=0, GID=0
        Preferred I/O block size     : 4096 bytes
        Blocks allocated             : 200
        Last status change           : Tue, 21 Nov 17 21:28:18 +0530
        Last file access             : Thu, 28 Dec 17 00:53:27 +0530
        Last file modification       : Tue, 21 Nov 17 21:28:18 +0530
        Hash                         : 9f0312d130016d103aa5fc9d16a2437e

Stats for /home/lab/linux-4.14-rc8:
        Elapsed time     : 1.305767 s
        Start time       : Sun, 07 Jan 18 03:42:39 +0530
        Root hash        : 434e93111ad6f9335bb4954bc8f4eca4
        Hash type        : md5
        Depth            : 8
        Total,
                size           : 66850916 bytes
                entries        : 12484
                directories    : 763
                regular files  : 11715
                symlinks       : 6
                block devices  : 0
                char devices   : 0
                sockets        : 0
                FIFOs/pipes    : 0

Allgemeine Ratschläge sind immer willkommen, aber die besten Antworten sind spezifisch und gegebenenfalls mit Code versehen. Wenn Sie Erfahrung in der Verwendung des Tools haben, auf das Sie sich beziehen, geben Sie dies bitte an.
Bu5hman

@ bu5hman Sicher! Es war mir nicht recht angenehm, mehr darüber zu sagen, wie gut es funktioniert, seit ich an seiner Entwicklung beteiligt bin.
Sechs-k

0

Individuell für alle Dateien in jedem Verzeichnis.

# Calculating
find dir1 | xargs md5sum > dir1.md5
find dir2 | xargs md5sum > dir2.md5
# Comparing (and showing the difference)
paste <(sort -k2 dir1.md5) <(sort -k2 dir2.md5) | awk '$1 != $3'

0

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 :

Das Standardformat für GNU tar wird zum Zeitpunkt der Kompilierung festgelegt. Sie können dies überprüfen tar --help, indem Sie die letzten Zeilen der Ausgabe ausführen und überprüfen . Normalerweise ist GNU tar so konfiguriert, dass Archive im gnuFormat erstellt werden. Zukünftige Versionen wechseln jedoch zu posix.

(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/%fin GNU Tar verwendet wird. In dieser Zeichenfolge wird der Bezeichner %pdurch 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:

( export LC_ALL=C
  find <paths> ! -type s -print0 |
  sort -z |
  tar cp --format=gnu --numeric-owner \
         --atime-preserve \
         --no-recursion --null --files-from - |
  md5sum --binary; )

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_ALLEinstellung lokal in einer Unterschale.

Außerdem verwende ich den Ausdruck ! -type smit find, 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-ownermit Tar, um später die Prüfsummen auch auf Systemen überprüfen zu können, bei denen nicht alle Dateibesitzer bekannt sind.

Die --atime-preserveOption 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 sortierten findAusgabe zugeführt wird.

Und schließlich ist es nicht wahr, dass ich benutze md5sum: Ich benutze tatsächlich sha256sum.


-1

Wenn Sie md5 nicht benötigen, können Sie es versuchen

find . -type f | xargs cksum | cksum

1
Die Frage fragt speziell nach md5
RalfFriedl
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.