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.

bagages non réclamés
la source
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.)
utilisateur619714
la source
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/{} \;
sborsky
la source
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 \;

Marc
la source
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
icyerasor
la source
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.

Dennis
la source
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.
Benjamin McGuire
la source
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.

porte-clés
la source
-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.

Phénix
la source
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