
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 +300m
was 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, cpio
aber 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 h
und t
sind einfache Möglichkeiten, das Verzeichnis und den Basisteil eines Dateinamens zu extrahieren. Rufen Sie auf, mkdir -p
um 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 rename
ist 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 echo
Elemente 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