Comment puis-je copier de manière récursive des fichiers par extension, en préservant la structure des répertoires?


71

Sur la ligne de commande Linux, j'aimerais copier un (très grand) ensemble de .txtfichiers d'un répertoire (et de ses sous-répertoires) à un autre.

J'ai besoin de la structure de répertoire pour rester intact et je dois ignorer les fichiers sauf ceux se terminant par .txt.


2
Avoir cp et find comme balises dans votre question signifie-t-il que vous êtes lié à ces options? Étant donné que votre jeu de données est très volumineux, il est logique de supposer que le processus de copie peut être interrompu pour certaines raisons et vous devrez le redémarrer. Je ne suis pas sûr que l’approche find / cp pourra reprendre le transfert et copier uniquement la partie manquante. Si vous n'êtes pas obligé de trouver / cp, vous pouvez envisager rsync, qui est plus intelligent. Son option --exclude vous permettra de sauter des fichiers .txt.
vtest

Appel équitable - rsync est probablement la meilleure option. Pas lié pour trouver / cp. (Je les ai utilisés de toute façon - rsync n'a pas été installé sur la machine distante, il était un serveur web , et je voulais partir aussi petit d'une empreinte possible)
unclaimedbaggage

Réponses:


95

Vous pouvez utiliser find et cpio pour le faire

cd /top/level/to/copy
find . -name '*.txt' | cpio -pdm /path/to/destdir

(-updm for overwrite destination content.)

pourquoi M? Je pensais qu'il était juste de conserver la date de modification du fichier.
Mubashar

7
cd /source/path
find -type f -name \*.txt -exec install -D {} /dest/path/{} \;

Vous manquez un .après find. Également sur macOS 10.13.1, cela a fonctionné:find . -type f -name "*.txt" -exec install -v {} /dest/path/{} \;
sinistre,

2

Une autre approche

find . -name '*.txt' -exec rsync -R {} path/to/dext \;


J'aime cette solution. J'avais l'habitude find . -iname '*.txt' -exec rsync -Rptgon {} path/to/dext \;de faire une correspondance insensible à la casse et de préserver la propriété et les autorisations.
MountainX

1

Le moyen le plus simple qui a fonctionné pour moi:

cp --parents -R jobs/**/*.xml ./backup/

Un problème est que vous devez accéder au répertoire "souhaité" avant que le "chemin parent" soit correct.

Assurez-vous également que vous avez activé les globes récursifs dans bash:

shopt -s globstar

1

que diriez-vous d'abord copiez-le avec

cp -r /old/folder /new/folder

puis allez dans le nouveau dossier et lancez

find . -type f ! -iname "*.txt" -delete

ou juste

cp -r /old/folder /new/folder && find . -type f ! -iname "*.txt" -delete

Edit: ok vous voulez une commande qui filtre (je ne l’ai pas testée car mon système n’a pas la cpiocommande!). Voici où je l'ai trouvé: http://www.gnu.org/software/findutils/manual/html_mono/find.html#Copying-A-Subset-of-Files

find . -name "*.txt" -print0 |
     cpio -pmd0 /dest-dir

Veuillez d'abord tester ceci, car je ne l'ai pas encore essayé. Si quelqu'un vérifiait, ce serait génial.


nods Cheers - cela fonctionnerait, mais sans filtrer au format .txt, je regarde quelques millions de fichiers (quelques centaines de Go). Si besoin est, je serais obligé de le faire, mais j'adorerais filtrer lors de la copie, si possible.
Unclaimedbaggage

1
Cheers, version éditée fonctionne si je retire le « 0 » de -pmd0
unclaimedbaggage

Vous devriez garder le 0dans -pmd0et ajouter -print0à la fin de la findcommande (juste avant le |).
G-Man

1

J'essayais de faire la même chose sur macOS, mais aucune des options ne fonctionnait vraiment pour moi. Jusqu'à ce que je découvre ditto.

Je devais copier beaucoup de fichiers .wav, et le laisser passer les fichiers vidéo ... Voici donc ce que je propose:

find . -type f -iname "*.wav" -ls -exec ditto {} /destination/folder/{} \;

  • find .- Fonctionne dans le dossier en cours. assurez-vous cd /source/folderavant de commencer

  • -type f - Spécifie de ne rechercher que des fichiers

  • -iname "*.wav" - Cela lui dit de chercher insensible à la casse * .wav
  • -ls- Cela vous montre le fichier sur lequel il travaille. Sinon, ça ne montre rien.
  • -exec ditto {} /destination/folder/{} \; - Fait tout le travail de copie et de création des fichiers avec la même arborescence.

0

Naviguez vers le répertoire:

find . -regex '<regexp_to_get_directories_and_files_you_want>' | xargs -i cp -r --parents {} path/to/destination

C’est un peu plus simple et puissant si vous gérez les expressions régulières.


-1

Naviguez vers le répertoire:

cp '*.css' /path/to/destination

Vous devrez accéder à chaque dossier du répertoire, mais c'est mieux que la plupart des options que j'ai vues jusqu'à présent.


Cette méthode n'est pas récursive, ce qui signifie que pour les grands annuaires, vous pourriez le faire pendant un bon bout de temps ...
Iain Reid
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.