Copie d'un seul fichier dans plusieurs répertoires à l'aide de cp

12

Cette question est une sorte de suite à ma question précédente, Création de nombreux répertoires à l'aidemkdir .

J'utilise la bashcoque. J'ai créé cinquante répertoires, chacun commençant par le préfixe "s", à l'aide de la commande:

mkdir $(printf "s%02i " $(seq 1 50))

qui remplit le deuxième chiffre avec des zéros. Autrement dit, les répertoires que j'obtiendrai sont de la forme s01, s02..., s49, s50.

Maintenant, je voudrais utiliser cppour copier un seul fichier (par exemple, test.txt) dans chacun des cinquante répertoires. Est-il possible de faire cela d'une manière analogue à celle ci-dessus? Par exemple, est-ce que le travail suivant fonctionnerait? Je suis relativement nouveau sur Unix / Linux, donc je ne veux pas vraiment essayer jusqu'à ce que quelqu'un me donne une indication qu'il est sûr.

cp test.txt $ (printf "s% 02i.txt" $ (seq 1 50))

En regardant la manpage cp, il ne semble pas que cpplusieurs destinations comme celle-ci soient prises en charge, cependant:

NAME
       cp - copy files and directories

SYNOPSIS
       cp [OPTION]... [-T] SOURCE DEST
       cp [OPTION]... SOURCE... DIRECTORY
       cp [OPTION]... -t DIRECTORY SOURCE...

DESCRIPTION
       Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY.

       Mandatory  arguments  to  long  options are mandatory for short options
       too.
Andrew
la source

Réponses:

7

Si vous souhaitez utiliser la sortie de votre commande pour copier le fichier dans chaque répertoire à l'aide cp, vous pouvez toujours le diriger vers xargs:

printf "s%02i " $(seq 1 50) | xargs -n 1 cp test.txt

Il ne devrait pas y avoir de soucis concernant la sécurité de l'analyse de la sortie puisque vous connaissez son format et son contenu à l'avance - le risque de rencontrer des méta-caractères et de l'espace dans les noms de fichiers n'est pas vraiment un problème ici.

Alternativement, en supposant que les répertoires existent déjà, vous pouvez essayer quelque chose comme:

find . -maxdepth 1 -type d -name 's[0-9][0-9]' -print0 | xargs -0 -I {} cp test.txt {}

ou sans tuyau:

find . -maxdepth 1 -type d -name 's[0-9][0-9]' -exec cp test.txt {} \;

Les deux dernières commandes trouveront tous les fichiers dans le répertoire courant et cp test.txtpour eux. L' -maxdepth 1option évitera également aux sous-répertoires de recevoir le fichier. Soyez averti que la 's[0-9][0-9]'correspondance est ssuivie de deux chiffres, ce qui signifie que si, pour une raison quelconque, vous avez s99dans le cwd, il recevra également une copie de test.txt.

tojrobinson
la source
8

Vous pouvez également laisser le shell effectuer les itérations avec une forboucle. C'est le moyen le plus basique qui ne repose pas sur des outils externes comme parallelou xargs, et je trouve cela plus facile à comprendre:

for name in $(printf "s%02i " $(seq 1 50)); do
    mkdir $name
    cp test.txt $name
done

Il existe un million d'autres façons d'écrire ceci, par exemple:

for name in $(seq -w 1 50); do
    mkdir s$name
    cp test.txt s$name
done

Si vous voulez vérifier ce qui serait exécuté avant de le faire, vous pouvez faire quelque chose comme ajouter les commandes avec echo, qui affichera la ligne plutôt que de l'exécuter:

for name in $(seq -w 1 50); do
    echo mkdir s$name
    echo cp test.txt s$name
done

les sorties:

mkdir s01
cp test.txt s01
mkdir s02
cp test.txt s02
mkdir s03
cp test.txt s03
# etc.
Jim Paris
la source
2

Vous pouvez également utiliser GNU parallel . En supposant que vous êtes dans le répertoire contenant text.txt et que vos 50 répertoires se trouvent dans /my/50dirs/path(comme /my/50dirs/path/s01, /my/50dirs/path/s02etc.), vous exécuteriez:

seq -w 01 50 | parallel -j1 cp text.txt /my/50dirs/path/s{}
don_crissti
la source
2
Mieux vaut le faire parallel -j1, sinon il y aura un travail par cœur, et sur une machine multicœur, les travaux seront en concurrence pour les E / S.
Gilles 'SO- arrête d'être méchant'