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.
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. ;-)
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
. ;-)
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.
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.Celui-ci a fonctionné pour moi:
find -name "*.csv" | xargs cp --parents -t /target
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/
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é.