Déplacer des millions de fichiers vers un répertoire différent avec des modèles de noms spécifiques

10

J'ai des millions de fichiers avec la nomenclature suivante sur une machine Linux:

1559704165_a1ac6f55fef555ee.jpg

Les 10 premiers chiffres sont horodatés et ceux suivis d'un _sont des identifiants spécifiques. Je souhaite déplacer tous les fichiers correspondant à des ID de nom de fichier spécifiques dans un dossier différent.

J'ai essayé cela sur le répertoire avec des fichiers

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

Cependant, je reçois une erreur indiquant:

bash 1559704165_a1ac6f55fef555ee.jpg: command not found

Lorsque j'ai essayé, mv ??????????_a1ac*.jpg je reçois une liste d'arguments trop longue. J'ai au moins 15 modèles de nom de fichier différents. Comment les déplacer.

Abricot
la source
1
Le bash dit tout: il essaie d' exécuter ce nom de fichier car il est le premier sur la ligne du 2ème étage du tuyau (votre tuyau du 2ème étage est | ??????????_a1ac*.jpg:: bash le développe en plusieurs noms de fichier, le premier étant 1559704165_a1ac6f55fef555ee.jpg, si vous vous retrouvez , dans cette 2ème étape de pipe, en essayant d'exécuter 1559704165_a1ac6f55fef555ee.jpg next_matching_filename 3rd_matching_filename ... nth_matching_filename:. Je suppose que vous avez plutôt essayé de filtrer sur ce nom de fichier (voir les réponses ci-dessous pour cela)
Olivier Dulac

Réponses:

15

Tu devrais utiliser:

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

maxdepth 1Cela signifie donc que vous ne souhaitez rechercher dans le répertoire actuel aucun sous-répertoire.

type f signifie trouver uniquement les fichiers.

name '??????????_a1ac*.jpg' est un modèle qui correspond au fichier que vous recherchez.

mv -t destination "{}" +signifie déplacer les fichiers correspondants vers la destination. Ici +ajoute de nouveaux fichiers correspondants au précédent comme:

mv -t dest a b c d

Ici abcd sont des fichiers différents.

Prvt_Yadav
la source
Merci d'avoir répondu avec concision à cette question. Plutôt que de simplement vider une solution, vous pourriez peut-être expliquer comment / quoi / pourquoi. Au lieu d'être utile à une personne, une fois, il peut être utile à tout le monde, tout le temps. La même question a été posée et répondue un nombre incalculable de fois au cours des 40 à 50 dernières années. Le problème est que ce n'est jamais bien expliqué. Apprenez à un homme à pêcher. En attendant: gnu.org/software/findutils/manual/html_node/find_html/… et comme c'est souvent le cas Wikipédia est plus utile que les documents officiels: en.wikipedia.org/wiki/Find_ ( Unix)
voix
Voir la réponse mise à jour.
Prvt_Yadav
Notez qu'il -ts'agit d'une extension GNU et peut donc ne pas être disponible sur d'autres types de dérivés UNIX.
Kevin
Lorsque vous dites "Les guillemets doubles empêchent la division des mots". Je suppose que vous faites allusion "{}", auquel cas je tiens à souligner qu'il {}n'est pas développé par le shell et n'a pas besoin d'être cité. Le shell passe {}pour trouver, et find le voit {}et le remplace par des chemins d'accès. Find exec n'utilise pas l'analyseur shell et n'effectue pas de fractionnement de mots. Le citer ne fait pas de mal, c'est juste que la justification donnée est un peu inexacte.
jw013
@ jw013 merci.
Prvt_Yadav
11

Votre commande,

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

Pipes la liste de tous les fichiers vers tous les fichiers!

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

fera l'affaire.

waltinator
la source
1
merci beaucoup ... votre solution a fonctionné aussi ... merci de m'avoir fait savoir où je me suis trompé
Apricot
8

Tu es très proche. Vous devez utiliser l' -nameoption pour find. Et n'oubliez pas de citer le motif.

Donc

find . -maxdepth 1 -type f -name '??????????_a1ac*.jpg' |xargs mv -t "/home/ubuntu/ntest"
Stephen Harris
la source
Merci beaucoup ... votre solution a fonctionné aussi ... merci supplémentaire de m'avoir fait savoir que j'étais proche de la solution .... c'est une motivation pour un novice comme moi
Apricot
1
vous devez ajouter a -print0comme dernier argument à la recherche (au lieu de la valeur par défaut: -print), et ajouter a -0comme première option à xargs (ie :) xargs -0 mv -t "/home/ubuntu/ntest". de cette façon, toutes sortes de noms de fichiers étranges (avec des espaces dedans, avec "newline" dedans, etc.) peuvent être gérés. find . -maxdepth 1 -type f -name '??????????_a1ac*.jpg' -print0 |xargs -0 mv -t "/home/ubuntu/ntest" (fonctionne uniquement avec la recherche de type GNU, cependant)
Olivier Dulac
2

Pas aussi "bon" que les findsolutions, mais une autre solution valable est de rendre les mvcommandes plus granulaires.

Cela fait 4096 mouvements, avec moins de fichiers déplacés par mvopération.

FILEPAT=a1ac
for i in $(seq $((0x000)) $((0xfff))); 
do 
   H=$(printf '%x\n' $i)
   mv 1559704165_${FILEPAT}${H}*.jpg /home/ubuntu/ntest
done
RonJohn
la source
C'est un hack intelligent pour ceux qui n'en ont pas find(pour une raison quelconque).
forêt le
-1

Si vous souhaitez déplacer des fichiers sur le même système hôte, ce que je suppose que vous faites avec votre mv, rsyncpourrait être une option plus rapide:

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

--inplaceet -Wsont configurés pour accélérer le processus.

Si cela donne une autre liste d'arguments erreur trop longue, vous pouvez alimenterrsync

Faites la liste avec find, par exemple

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

et donnez-le à rsync

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

La source ici est /path/to/files, car rsynctraitera la liste que vous lui donnez par rapport à votre source.


Le point étant: rsyncest plus rapide que mvsi les fichiers ne sont pas sur le même système de fichiers .

Robert Riedl
la source
Cela risque de frapper la même erreur de "liste d'arguments trop longue" mentionnée par l'OP
Grump
@Grump, pour éviter cela, OP pourrait écrire la liste des fichiers à copier dans un fichier, c'est find . -maxdepth 1 -type f -name '??????????_a1ac*.jpg' > /tmp/my_image_list.txt-à- dire puis la passer à rsync avec --files-from=/tmp/my_image_list.txt. Le fait étant que rsyncc'est plus rapide. Sauf si les fichiers résident sur le même système de fichiers, qu'OP n'a pas indiqué.
Robert Riedl
@RobertRiedl: vous devez modifier votre réponse et ajouter ces informations. Les commentaires peuvent être impermanents.
NickD
@NickD, j'ai mis à jour ma réponse.
Robert Riedl