Comment déplacer récursivement tous les fichiers des sous-répertoires vers un seul répertoire?

10

J'essaye de rassembler tous les fichiers sous le répertoire courant et tous les sous-répertoires dans un répertoire. J'essaye quelque chose comme le suivant

find -type f -exec mv {} collection/{} \; 

la commande ci-dessus ne fonctionnera pas car la seconde {}donne le chemin complet, comment puis-je collecter tous les fichiers?

Lapin
la source

Réponses:

14

Retirez le {}de mv, mvprendra comme répertoire cible en ignorant les répertoires parents:

find -type f -exec mv {} collection/ \;
Lekensteyn
la source
ohh ça ne m'est pas venu à l'esprit. merci :)
Bunny Rabbit
Comme je l'ai dit dans ma réponse à la question, c'est potentiellement une mauvaise idée. Peut-être que l'utilisation de l'argument -maxdepth 1aiderait.
loevborg
À bien y penser, il semble que j'ai mal lu votre question :) Désolé.
loevborg
@loevborg: J'ai ajouté "récursivement" au titre maintenant. S'il y a encore de la confusion, veuillez l'éditer et l'améliorer :)
Lekensteyn
1
une variation plus rapide de cette réponse estfind -type f -print0|xargs -0r mv -it colection/
hildred
5

Au lieu d'utiliser find(qui fait bien le travail), vous pouvez également utiliser le shell à cette fin.

Disons que vous voulez tous les fichiers de $ PWD à $ DEST. La tentative naturelle serait:

mv $PWD/* $DEST

Comment cela marche-t-il? L'expression "$ PWD / *" s'étend aux noms de tous les fichiers de ce répertoire. Cette fonction shell est appelée "globbing". Le dernier argument de mvest le répertoire de destination. Si vous avez de très nombreux fichiers, cela ne fonctionnera pas car la longueur de la ligne de commande est limitée.

Mais la solution a le problème d'omettre les fichiers de points - ou les fichiers, fichiers et répertoires "cachés" dont le nom commence par un ".". Pour résoudre ce problème, vous devez dire à votre shell d'inclure des fichiers dot lors de la globalisation. Pour ce faire, utilisez

shopt -s dotglob

lors de l'utilisation bash(et vous l'utilisez probablement, bashsauf si vous avez modifié la valeur par défaut). Dans ce shell, la commande ci-dessus fonctionnera également pour les fichiers dot.

En passant, dans zsh, vous avez la possibilité de le choisir au cas par cas. Pour ce faire, mettez

setopt extendedglob

dans votre .zshrc. Ensuite, vous pouvez utiliser

mv $PWD/*(D) $DEST

pour déplacer tous les fichiers, y compris les fichiers dot. (Le "D" a pour effet d'activer temporairement l'option "GLOB_DOTS").

Maintenant, la question d'origine était de déplacer tous les fichiers normaux (pas les répertoires) de tous les sous-répertoires et leurs sous-répertoires vers un seul répertoire. Cela peut être accompli avec zsh:

mv $PWD/**/*(D.)

Ici, l'expression **/*fait descendre le globber récursivement dans des sous-répertoires. Le Dmoyen "sélectionne également les fichiers dot", le .moyen "ne sélectionne que les fichiers normaux, pas les répertoires".

Loevborg
la source
eh bien, je voulais aussi récursivement dans tous les sous-répertoires, mais merci de toute façon les informations sont utiles, rencontrez cette situation trop souvent :)
Bunny Rabbit
En fait, find n'est pas exagéré pour cela, le globbing sélectionnera toutes les correspondances, pas seulement les fichiers, mais aussi les répertoires. Si vous êtes inquiétudes sur les performances, vous pouvez aussi utiliser quelque chose comme: find -type f -exec mv -t collection/ {} +. Consultez la page de manuel pour savoir comment cela fonctionne.
Lekensteyn
Lekensteyn, vous avez raison. J'ai mis à jour la réponse maintenant que j'ai compris la question.
loevborg
2
Merveilleuse réponse, dommage qu'elle ne soit pas particulièrement pertinente pour la question :).
crazy2be