Extrahieren identischer Dateien aus zwei Verzeichnissen

Extrahieren identischer Dateien aus zwei Verzeichnissen

Ich suche eine Linux-Lösung für folgendes Problem:

Gegeben seien zwei Verzeichnisse mit einer großen Anzahl von Dateien. Alle Dateinamen sind in beiden Verzeichnissen zufällig und unterschiedlich. Der Inhalt einiger Dateien in den beiden Verzeichnissen ist jedoch identisch.

Ich möchte alle Dateien, die in beiden Verzeichnissen vorkommen, in ein drittes Verzeichnis kopieren. („In beiden vorkommen“ bedeutet, dass sie denselben Inhalt und nicht denselben Namen haben.)

Antwort1

Vorausgesetzt, Ihre Dateinamen enthalten keine Leerzeichen und in keinem der Verzeichnisse sind Unterverzeichnisse vorhanden, werden im Folgenden Dateinamenpaare mit übereinstimmenden MD5-Summen gedruckt:

join -o 1.2,2.2 <(md5sum $D1/* | sort) <(md5sum $D2/* | sort)

Um nur einen der Dateinamen zu erhalten, verwenden Sie -o 1.2oder -o 2.2.

Wenn Dateinamen (oder Pfade) Leerzeichen enthalten könnten, müssen Sie geschickter vorgehen.

Wenn ein einzelnes Verzeichnis dieselbe Datei unter mehreren Namen enthalten könnte, müssen Sie ebenfalls cleverer vorgehen – und genau entscheiden, was zu tun ist. Eine Möglichkeit wäre, die Duplikate vor dem Zusammenführen herauszufiltern:

join -o 1.2,2.2 <(md5sum $D1/* | sort | uniq -w16) \
                <(md5sum $D2/* | sort | uniq -w16)

VERWENDE NICHTsum

sumgibt eine 16-Bit-Prüfsumme aus; wenn Sie auch nur ein paar hundert Dateien in jedem Verzeichnis haben, ist es wahrscheinlich, dass Sie ein falsches Positiv erhalten, wenn Sie 16-Bit-Prüfsummen vergleichen. md5sumist auch nicht absolut sicher, aber die Wahrscheinlichkeit einer Kollision mit 128-Bit-Prüfsummen ist gering. Im Zweifelsfall und wenn es wirklich wichtig ist, cmpauch die Dateien:

join -o 1.2,2.2 <(md5sum $D1/* | sort) <(md5sum $D2/* | sort) |
while read F1 F2; do
  if cmp -s $F1 $F2; then
    cp F1 $D3
  fi
done

(Auch dies funktioniert nicht, wenn die Dateinamen Leerzeichen enthalten könnten.)

Antwort2

Verwenden Sie Ihre bevorzugte Shell für diesen Pseudocode:

cd D1; sum * | while read l; do echo "D1 $l"; done >/tmp/foo
cd D2; sum * | while read l; do echo "D2 $1"; done >>/tmp/foo

sort -n /tmp/foo | awk '
$1 == prev_cs { echo "cp $3 dest"}
     /prev_cs = $1/
' | shell

Sie können die awk-Ausgabe zur Überprüfung speichern, bevor Sie die Kopien ausgeben, wenn Sie möchten

Antwort3

dies könnte funktionieren, ebenso wie die Antwort von mpez0 zum Kopieren der Duplikate.

find {tst1,tst2} -exec sum {} {} \; 2> /dev/null | sort | uniq

verwandte Informationen