Skript zum Deduplizieren von Dateien und Ordnern mit einem bestimmten Suffix

0

Eine verpfuschte OneDrive-Wiederherstellung hat mir viele Dateien und Ordner mit dem Suffix "(1)" oder "(2)" hinterlassen.

Ich hätte gerne ein Skript (Bash ist in Ordnung, da ich MinGW + Cygwin oder PowerShell habe), das alle Dateien und Ordner in einem bestimmten Ordner (z. B. "d: \ OneDrive" oder "/ cygdrive / d / OneDrive") und für 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 regulären Ausdruck "\ 1 \ s * \ (\ d + \) \. \ 2" mit "\ 1" übereinstimmt "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 mit allen Dateien / Ordnern vergleichen, die von der vorherigen Regex gefunden wurden (im letzteren Fall rekursiv), und falls sie identisch sind, sollte es die Kopie löschen (die mit dem längeren Dateinamen).

Während eine mögliche Grundstruktur des Skripts klar ist (zwei verschachtelte für Schleifen, Suchen zum Finden von Dateien, die der regulären Ausdrücke entsprechen, Diff zum Vergleich usw.), kenne ich mich mit Bash-Skripten nicht aus, um die Teile bequem zusammenzusetzen, und es kann gut sein in jedem Fall eine effizientere Struktur sein (was angesichts der Tatsache, dass etwa eine halbe Million Dateien zu durchlaufen sind, hilfreich wäre).

cfp
quelle
Ich würde ein bisschen mehr Aufwand von Ihrer Seite erwarten, Super User ist kein Skriptschreibdienst. Auch mit PowerShell würde ich anfangen, eine Get-FileHashund eine Gruppe nach Hashes zu erstellen, wobei der kürzeste Name beibehalten wird - der andere wird verworfen.
LotPings
Gerechter Kommentar! Ich habe jetzt einen ersten Versuch hinzugefügt, der gerade läuft. Es wurde noch nichts gedruckt, was entweder bedeutet, dass ein Fehler vorliegt oder dass es schrecklich langsam ist.
cfp
Da es sich um eine einmalige Operation handelt, können Sie WinMerge auch manuell verwenden, um Verzeichnisse zu vergleichen. Das Auffinden von Ordnern mit (1) oder (2) sollte ziemlich einfach sein und auch immer dann überprüft werden, wenn ein Ordner ohne dieses Suffix vorhanden ist.
Seth
Es gibt ungefähr eine halbe Million Dateien in dem Ordner und seinen Unterordnern und (mit einer Schätzung) mindestens 10.000 solcher Dateien / Ordner, die auf (1) oder (2) enden. Es wäre ziemlich schmerzhaft, WinMerge so oft manuell aufzurufen.
cfp
Das gleiche Grundproblem, andere Frage: hier .
Kamil Maciorowski

Antworten:

0

Hier ist ein Skript, das funktioniert und einigermaßen effizient ist. Beachten Sie, dass genau ein Leerzeichen vor dem "(1)" und keines nach dem "(1)" eingefügt werden muss, 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 '{print length($0)"\t"$0}' | 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
cfp
quelle