Skript zum Deduplizieren von Dateien und Ordnern mit einem bestimmten Suffix

339
cfp

Bei einer verpatzten OneDrive-Wiederherstellung sind viele Dateien und Ordner mit einem Suffix "(1)" oder "(2)" hinterlassen worden.

Ich hätte gerne ein Skript (Bash ist in Ordnung, da ich MinGW + Cygwin oder PowerShell habe), das alle Dateien und Ordner innerhalb eines bestimmten Ordners (z. B. "d: \ OneDrive" oder "/ cygdrive / d / OneDrive") analysiert Überprüfen Sie für jede Datei oder jeden Ordner, ob sich eine oder mehrere Dateien / Ordner (im selben Unterordner) befinden, deren Datei- / Ordnername mit dem Regex "\ 1 \ s * \ (\ d + \) \. \ 2" übereinstimmt, wobei "\ 1 "ist der ursprüngliche Datei- / Ordnername ohne Erweiterung und \ 2 ist die ursprüngliche Erweiterung. Dann sollte das Skript die ursprüngliche Datei / den ursprünglichen Ordner binär mit den Dateien / Ordnern vergleichen, die von der vorherigen Regex gefunden wurden (im letzteren Fall rekursiv). Wenn sie identisch sind, sollte sie die Kopie (die mit dem längeren Dateinamen) löschen.

Während eine mögliche Grundstruktur des Skripts klar ist (zwei verschachtelte Schleifen, zum Finden von Dateien, die mit dem Regex übereinstimmen, diff zum Vergleich usw.), kenne ich Bash-Skripts nicht, um die Teile bequem zusammenzusetzen, und das kann gut sein in jedem Fall eine effizientere Struktur sein (was helfen würde, da ungefähr eine halbe Million Dateien durchgegangen sind).

0
Ich würde ein bisschen mehr Aufwand von Ihrer Seite erwarten, [SU] ist kein Skriptschreibservice. Mit PowerShell würde ich auch ein "Get-FileHash" und eine Gruppe von Hashes erstellen und dabei den kürzesten Namen behalten - den anderen verwerfen. LotPings vor 5 Jahren 0
Fairer Kommentar! Ich habe jetzt einen ersten Versuch hinzugefügt, der gerade läuft. Bis jetzt wurde noch nichts gedruckt, was entweder bedeutet, dass es einen Fehler gibt oder dass es furchtbar langsam ist. cfp vor 5 Jahren 0
Da es sich um eine einmalige Operation handelt, können Sie WinMerge, das Verzeichnisse vergleichen kann, nicht manuell verwenden. Das Finden von Ordnern mit (1) oder (2) darin sollte ziemlich einfach sein und auch prüfen, wann ein Ordner ohne dieses Suffix existiert. Seth vor 5 Jahren 0
Es gibt ungefähr eine halbe Million Dateien in dem Ordner und seinen Unterordnern und (vermutlich) mindestens 10.000 solcher Dateien / Ordner, die auf (1) oder (2) enden. Manuelles Aufrufen von WinMerge, so oft, wäre ziemlich schmerzhaft. cfp vor 5 Jahren 0
Das gleiche Grundproblem, andere Frage: [hier] (https://superuser.com/q/1338324/432690). Kamil Maciorowski vor 5 Jahren 0
Vielen Dank für den Link zu dieser anderen Frage. Ich habe jetzt meine eigene Frage mit einem Skript beantwortet, das scheinbar funktioniert, obwohl es schrecklich ineffizient ist. Wenn jemand eine schnellere Version produzieren kann, wäre das sehr zu begrüßen. cfp vor 5 Jahren 0

1 Antwort auf die Frage

0
cfp

Hier ist ein Skript, das funktioniert und ziemlich effizient ist. Beachten Sie, dass vor dem "(1)" genau ein Leerzeichen hinzugefügt wurde und danach kein Platz hinzugefügt wurde, damit es funktioniert.

#!/usr/bin/bash IFS=$'\n'; set -f #Go deepest first to deal with copies within copied folders. for copy in $(find . -regextype posix-egrep -regex "^.*\ \([0-9]+\)\s*(\.[^/.]*)?$" | awk '' | sort -rnk1 | cut -f2-); do orig=$(rev <<< "$copy" | sed -E 's/\)[0-9]+\(\ //' | rev) if [ "$orig" != "$copy" ]; then if [ -f "$orig" ]; then if [ -f "$copy" ]; then echo "File pair: $orig $copy" if diff -q "$orig" "$copy" &>/dev/null; then echo "Removing file: $copy" rm -f "$copy"; fi fi  fi if [ -d "$orig" ]; then if [ -d "$copy" ]; then echo "Folder pair: $orig $copy" if rmdir "$copy" &>/dev/null; then #If the "copy" was an empty directory then we've removed it and so we're done. echo "Removed empty folder: $copy" else #Non-destructively ensure that both folders have the same files at least.  rsync -aHAv --ignore-existing "$orig/" "$copy" &>/dev/null rsync -aHAv --ignore-existing "$copy/" "$orig" &>/dev/null if diff -qr "$orig" "$copy" &>/dev/null; then echo "Removing folder: $copy" rm -rf "$copy"; fi  fi fi fi fi done unset IFS; set +f