Verschieben von Millionen von Dateien in ein anderes Verzeichnis mit bestimmten Namensmustern

10

Ich habe Millionen von Dateien mit der folgenden Nomenklatur auf einem Linux-Computer:

1559704165_a1ac6f55fef555ee.jpg

Die ersten 10 Ziffern sind Zeitstempel und diejenigen, denen ein folgt, _sind spezifische IDs. Ich möchte alle Dateien, die mit bestimmten Dateinamen-IDs übereinstimmen, in einen anderen Ordner verschieben.

Ich habe dies im Verzeichnis mit Dateien versucht

find . -maxdepth 1 -type f | ??????????_a1ac*.jpg |xargs mv -t "/home/ubuntu/ntest"

Ich erhalte jedoch eine Fehlermeldung:

bash 1559704165_a1ac6f55fef555ee.jpg: command not found

Wenn ich es versucht habe, mv ??????????_a1ac*.jpg erhalte ich einen zu langen Fehler in der Argumentliste. Ich habe mindestens 15 verschiedene Dateinamenmuster. Wie bewege ich sie?

Aprikose
quelle
1
Die Bash sagt alles: Sie versucht , diesen Dateinamen auszuführen , da er der erste in der Zeile in der 2. Stufe der Pipe ist (Ihre Pipe der 2. Stufe lautet | ??????????_a1ac*.jpg:: Bash erweitert ihn auf mehrere Dateinamen, die erste ist 1559704165_a1ac6f55fef555ee.jpg, wenn Sie am Ende sind In dieser zweiten Pipe-Phase haben 1559704165_a1ac6f55fef555ee.jpg next_matching_filename 3rd_matching_filename ... nth_matching_filenameSie versucht, Folgendes auszuführen: Ich denke, Sie haben stattdessen versucht, nach diesem Dateinamen zu filtern (siehe Antworten unten)
Olivier Dulac

Antworten:

15

Du solltest benutzen:

find . -maxdepth 1 -type f -name '??????????_a1ac*.jpg' \
-exec mv -t destination "{}" +

Das maxdepth 1heißt also, dass Sie im aktuellen Verzeichnis keine Unterverzeichnisse suchen möchten.

type f bedeutet, nur Dateien zu finden.

name '??????????_a1ac*.jpg' ist ein Muster, das mit der gesuchten Datei übereinstimmt.

mv -t destination "{}" +bedeutet, übereinstimmende Dateien an das Ziel zu verschieben. Hier werden +neue übereinstimmende Dateien zu vorherigen hinzugefügt, wie:

mv -t dest a b c d

Hier abcd sind verschiedene Dateien.

Prvt_Yadav
quelle
Vielen Dank für die präzise Beantwortung dieser Personenfrage. Anstatt einfach eine Lösung zu entleeren, könnten Sie vielleicht erklären, wie / was / warum. Anstatt für eine Person einmal nützlich zu sein, kann es für jeden jederzeit nützlich sein. Dieselbe Frage wurde in den letzten 40-50 Jahren unzählige Male gestellt und beantwortet. Das Problem ist, es wird nie gut erklärt. Bringen Sie einem Mann das Fischen bei. In der Zwischenzeit: gnu.org/software/findutils/manual/html_node/find_html/… und wie so oft ist Wikipedia nützlicher als die offiziellen Dokumente: en.wikipedia.org/wiki/Find_ ( Unix)
Stimmen
Siehe aktualisierte Antwort.
Prvt_Yadav
Beachten Sie, dass -tes sich um eine GNU-Erweiterung handelt und daher möglicherweise nicht für andere Arten von UNIX-Derivaten verfügbar ist.
Kevin
Wenn Sie sagen "Doppelte Anführungszeichen verhindern das Aufteilen von Wörtern." Ich nehme an, Sie beziehen sich auf "{}". In diesem Fall möchte ich darauf hinweisen, dass dies {}nicht durch die Shell erweitert wird und nicht zitiert werden muss. Die Shell geht vorbei {}, um zu finden und zu sehen, {}und ersetzt sie durch Pfadnamen. Find exec verwendet den Shell-Parser nicht und führt keine eigene Wortteilung durch. Das Zitieren schadet nicht, es ist nur so, dass die Begründung etwas ungenau ist.
jw013
@ jw013 danke.
Prvt_Yadav
11

Dein Befehl,

find . -maxdepth 1 -type f | ??????????_a1ac*.jpg |xargs mv -t "/home/ubuntu/ntest"

Leitet die Liste aller Dateien an alle Dateien weiter!

find . -maxdepth 1 -type f -name `*_a1ac*.jpg` -print0 |\
xargs  -0 -r mv -t "/home/ubuntu/ntest"

wird den Trick machen.

Walzer
quelle
1
Vielen Dank ... Ihre Lösung hat auch funktioniert ... Danke, dass Sie mich wissen ließen, wo ich falsch gelaufen bin
Apricot
8

Du bist sehr nah. Sie sollten die -nameOption verwenden, um find. Und denken Sie daran, das Muster zu zitieren.

So

find . -maxdepth 1 -type f -name '??????????_a1ac*.jpg' |xargs mv -t "/home/ubuntu/ntest"
Stephen Harris
quelle
Vielen Dank ... Ihre Lösung hat auch funktioniert ... zusätzlicher Dank, dass Sie mich wissen ließen, dass ich der Lösung nahe war ... es ist ein Motivator für einen Neuling wie mich
Apricot
1
Sie sollten a -print0als letztes Argument zum Suchen hinzufügen (anstelle des Standardarguments: -print) und -0xargs als erste Option hinzufügen (dh :) xargs -0 mv -t "/home/ubuntu/ntest". Auf diese Weise können alle Arten von seltsamen Dateinamen (mit Leerzeichen, "Zeilenumbruch" usw.) behandelt werden. find . -maxdepth 1 -type f -name '??????????_a1ac*.jpg' -print0 |xargs -0 mv -t "/home/ubuntu/ntest" (funktioniert nur mit GNU-ähnlichen Fund)
Olivier Dulac
2

Nicht so "gut" wie die findLösungen, aber eine andere gültige Lösung besteht darin, die mvBefehle detaillierter zu gestalten.

Dies führt 4096 Verschiebungen durch, wobei weniger mvOperationen pro Operation verschoben werden.

FILEPAT=a1ac
for i in $(seq $((0x000)) $((0xfff))); 
do 
   H=$(printf '%x\n' $i)
   mv 1559704165_${FILEPAT}${H}*.jpg /home/ubuntu/ntest
done
RonJohn
quelle
Dies ist ein kluger Hack für diejenigen ohne find(aus welchem ​​Grund auch immer).
Wald
-1

Wenn Sie Dateien auf demselben Hostsystem verschieben möchten, was Sie wahrscheinlich mit Ihrem tun mv, rsynckönnte dies eine schnellere Option sein:

rsync -av --inplace -W /source/??????????_a1ac*.jpg /home/ubuntu/ntest/

--inplaceund -Wsollen den Prozess beschleunigen.

Sollte dies zu einem zu langen Fehler einer anderen Argumentliste führen, können Sie Listen fütternrsync

Machen Sie die Liste zum Beispiel mit find

find . -maxdepth 1 -type f -name '??????????_a1ac*.jpg' > /tmp/my_image_list.txt

und gib es rsync

rsync -av --inplace -W --files-from=/tmp/my_image_list.txt /path/to/files /home/ubuntu/ntest/

Die Quelle hier ist /path/to/files, weil rsyncdie Liste, die Sie geben, als relativ zu Ihrer Quelle behandelt wird.


Der Punkt ist: rsyncist schneller als mv, wenn sich die Dateien nicht im selben Dateisystem befinden .

Robert Riedl
quelle
Dies wird wahrscheinlich den gleichen "Argument Liste zu lang" Fehler treffen, den das OP erwähnte
Grump
@Grump, um dies zu vermeiden, könnte OP die Liste der zu kopierenden Dateien in eine Datei schreiben, dh find . -maxdepth 1 -type f -name '??????????_a1ac*.jpg' > /tmp/my_image_list.txtan rsync mit übergeben --files-from=/tmp/my_image_list.txt. Der Punkt ist, dass rsyncschneller ist. Es sei denn, die Dateien befinden sich auf demselben Dateisystem, das OP nicht angegeben hat.
Robert Riedl
@RobertRiedl: Sie sollten Ihre Antwort bearbeiten und diese Informationen hinzufügen. Kommentare können unbeständig sein.
NickD
@ NickD, ich habe meine Antwort aktualisiert.
Robert Riedl