So verschieben Sie eine Datei rekursiv basierend auf der Größe und behalten die Struktur bei

So verschieben Sie eine Datei rekursiv basierend auf der Größe und behalten die Struktur bei

Ich möchte Dateien, die größer als "300 MB" sind, aus einem Verzeichnisbaum verschieben, in dem sich jede Datei in Unterordnern befindet

Beispiel: Ich habe eine Verzeichnisstruktur:

dirA/
dirA/file1
dirA/x/
dirA/x/file2
dirA/y/
dirA/y/file3

Hier ist das erwartete Ergebnis, ein „Verschieben“ des Verzeichnisbaums, bei dem jede Datei in die Unterordner verschoben wird:

dirB/            #  normal directory
dirB/file1       #  moved from dirA/file1
dirB/x/          #  normal directory
dirB/x/file2     #  moved from dirA/x/file2
dirB/y/          #  normal directory
dirB/y/file3     #  moved from dirA/y/file3

Aber find /path/ -type f -size +300mwas dann? Und leider enthalten manche der Dateien alle möglichen Zeichen, die Sie auch auf Ihrer Tastatur finden würden.

Ich habe mir das angesehenFadenwo jemand davon spricht, cpioaber ich kenne das Programm nicht ...

PS: Haben Sie GNU Parallel installiert, falls dies die Dinge beschleunigen könnte?

Antwort1

Der einfache Weg ist mitzshSie könnenGlob-Qualifikationum Dateien nach Kriterien wie Typ und Größe zuzuordnen. DiePlatzhaltermuster **/passt zu jeder Ebene von Unterverzeichnissen. DieVerlaufsmodifikatoren hund tsind einfache Möglichkeiten, das Verzeichnis und den Basisteil eines Dateinamens zu extrahieren. Rufen Sie auf, mkdir -pum die Verzeichnisse bei Bedarf zu erstellen.

cd dirA
for x in **/*(.Lm+300); do
  mkdir -p ../dirB/$x:h &&
    mv -- $x ../dirB/$x
done

Die portable Methode ist mit find. Verwenden Sie -exec, um für jede Datei einen Shell-Ausschnitt aufzurufen.

cd dirA
find . -type f -size +300000k -exec sh -c 'for x do
  mkdir -p "../dirB/${x%/*}"
  mv "$x" "../dirB/$x"
done' sh {} +

Die Parallelisierung ist für die Eingabe/Ausgabe selten sinnvoll: Sie können die Vorteile mehrerer CPUs nutzen, aber die CPU stellt bei der E/A selten einen Engpass dar.

Antwort2

Perl renameist die naheliegende Wahl. Es kann als ren, rename, oder installiert werden pren:

find dirA -type f -size +300M | ren 's:^dirA/:dirB/:'

Es funktioniert jedoch nicht, wenn die Dateien an einen anderen Einhängepunkt verschoben werden, und schlägt fehl, wenn die Verzeichnisse dort nicht vorhanden sind.

GNU Parallel wird langsamer sein:

cd dirA
find . -type f -size +300M | parallel mkdir -p ../dirB/{//}
find . -type f -size +300M | parallel mv {} ../dirB/{}

funktioniert aber auch, wenn die Kopier-und-Entfernen-Routine ausgeführt werden muss, um die Dateien auf ein anderes Dateisystem zu übertragen.

Antwort3

Zusamenfassend:

find dirA -type f -size +300m -printf "mv %p dirB/%P\n" | sh

Allerdings müssen alle Unterverzeichnisse in dirB vorhanden sein, bevor Sie beginnen. Aus diesem Grund empfehle ich Ihnen, die folgenden beiden Schritte auszuführen:

cd dirA
find . -type f -size +300m -printf "mkdir -p ../dirB/%h\nmv %p ../dirB/%P\n" | sh

Bezüglich cpio (tatsächlich löst es das Unterverzeichnisproblem):

(cd dirA; find . -type f -size +300m) | cpio -p -md  dirB

(Bezüglich des cp(1) im selben Thread, den Sie erwähnen, ist es nicht gut für Sie, weil es kopiert alle die Dateien Und Unterverzeichnis namens dirA unter dirB erstellen. Das Flag-Tkann dieses Problem lösen)

Antwort4

Dies sollte es abdecken.

find /path -type f -size +300m | while read A ; do DEST=${A/dirA/dirB} ; echo mkdir -p $(dirname $DEST) 2>/dev/null; echo mv $A $DEST ; done

Führen Sie es zunächst unverändert aus, führen Sie eine Plausibilitätsprüfung durch und führen Sie es, wenn Sie mit den vorgeschlagenen Befehlen zufrieden sind, ohne die echoElemente erneut aus.

In Ihrem Dateistrukturbeispiel würden die folgenden Befehle generiert

mkdir -p ./dirB
mv ./dirA/file1 ./dirB/file1
mkdir -p ./dirB/x
mv ./dirA/x/file2 ./dirB/x/file2
mkdir -p ./dirB/y
mv ./dirA/y/file3 ./dirB/y/file3

verwandte Informationen