web-dev-qa-db-fra.com

Copiez un type de fichier spécifique en conservant la structure du dossier

J'ai une structure de dossiers avec un tas de fichiers * .csv dispersés dans les dossiers. Maintenant, je veux copier tous les fichiers * .csv vers une autre destination en conservant la structure des dossiers.

Cela fonctionne en faisant:

cp --parents *.csv /target
cp --parents */*.csv" /target
cp --parents */*/*.csv /target
cp --parents */*/*/*.csv /target
...

et ainsi de suite, mais je voudrais le faire en utilisant une seule commande.

127
Mojo

Y a-t-il une raison pour laquelle les gens résistent à utiliser le -exec De find? C'est très pratique.

find . -name '*.csv' -exec cp --parents \{\} /target \;

Connaissez vos outils. ;-)

145
msb

Vous pouvez également utiliser rsync pour cela.

$ rsync -a --Prune-empty-dirs --include '*/' --include '*.csv' --exclude '*' source/ target/

Si vous souhaitez conserver des répertoires vides de l'arborescence source, ignorez --Prune-empty-dirs option:

$ rsync -a --include '*/' --include '*.csv' --exclude '*' source/ target/

Si vous voulez pas que les liens symboliques, les dates de modification, les autorisations de fichier, les propriétaires, etc. soient conservés, veuillez remplacer -a avec une autre combinaison de -rlptgoD. ;-)

51
Dubu

Vous pouvez utiliser find et cpio en mode pass through

find . -name '*.csv' | cpio -pdm  /target

Cela trouvera tous les fichiers .csv dans le répertoire actuel et ci-dessous et les copiera dans/target en maintenant la structure du répertoire enracinée dans ..

Si tu utilises

find /path/to/files -name '*.csv' | cpio -pdm /target

il trouvera tout le fichier dans /path/to/files et ci-dessous et copiez-les dans /target/path/to/files et plus bas.

36
user591

La commande cp autorise plusieurs arguments source:

cp **/*.csv --parents ../target

CAVEAT: J'utilise un glob récursif ici; il s'agit de l'option globstar dans Bash 4+ et ksh, et est prise en charge par défaut dans zsh. Les globs récursifs ne correspondent pas aux fichiers et dossiers cachés, et aux certaines implémentations suivent des liens symboliques tandis que d'autres ne le font pas .

Si votre shell ne prend pas en charge les globs récursifs, ou si vous préférez ne pas les utiliser, vous pouvez procéder comme suit:

  • *.csv */*.csv */*/*.csv */*/*/*.csv - ceci est bien sûr très redondant et nécessite de connaître la profondeur de la structure de votre répertoire.
  • $(find . -name '*.csv') - Ceci correspondra aux fichiers et dossiers cachés. find permet également de spécifier si les liens symboliques sont suivis ou non, ce qui peut être utile.
25
Kyle Strand

Celui-ci a fonctionné pour moi:

find -name "*.csv" | xargs cp --parents -t /target

17
marko

Depuis la page de manuel de rsync:

-R, - relatif

Utilisez des chemins relatifs. Cela signifie que les noms de chemin d'accès complets spécifiés sur la ligne de commande sont envoyés au serveur plutôt que seulement les dernières parties des noms de fichiers. Ceci est particulièrement utile lorsque vous souhaitez envoyer plusieurs répertoires différents en même temps. Par exemple, si vous avez utilisé cette commande:

rsync -av /foo/bar/baz.c remote:/tmp/

... cela créerait un fichier nommé baz.c dans/tmp/sur la machine distante. Si à la place vous avez utilisé

rsync -avR /foo/bar/baz.c remote:/tmp/

puis un fichier nommé /tmp/foo/bar/baz.c serait créé sur la machine distante, en conservant son chemin complet. Ces éléments de chemin supplémentaires sont appelés "répertoires implicites" (c'est-à-dire les répertoires "foo" et "foo/bar" dans l'exemple ci-dessus).

Donc, cela fonctionnerait aussi:

rsync -armR --include="*/" --include="*.csv" --exclude="*" /full/path/to/source/file(s) destination/
11
Geremia

En supposant que vous souhaitez répliquer cette structure à partir de ./source à ./destination:

cd source
find . -name "*.csv" | xargs tar cvf - | (cd ../destination ; tar xfp -)

Je suis prêt à compter cela comme une seule ligne, le cd source étant un shell intégré.

8
MadHatter