Comment copier un fichier dans plusieurs répertoires à l'aide de la commande gnu cp

210

Est-il possible de copier un seul fichier dans plusieurs répertoires à l'aide de la commande cp?

J'ai essayé ce qui suit, qui n'a pas fonctionné:

cp file1 /foo/ /bar/
cp file1 {/foo/,/bar}

Je sais qu'il est possible d'utiliser une boucle for ou de trouver. Mais est-il possible d'utiliser la commande gnu cp?

Tom Feiner
la source

Réponses:

106

Non, cppeut copier plusieurs sources mais ne copiera que vers une seule destination. Vous devez vous organiser pour invoquer cpplusieurs fois - une fois par destination - ce que vous voulez faire; en utilisant, comme vous le dites, une boucle ou un autre outil.

l'ombre de la lune
la source
Merci d'avoir répondu! Maintenant que j'y pense un peu plus, sans drapeaux supplémentaires (qui n'existent pas), cp ne saura pas quelle est la source et quel est le répertoire DEST.
Tom Feiner
10
Ce n'est pas la bonne réponse. Veuillez voir la réponse de Robert Gamble.
PlagueHammer
23
@Nocturne: quelle partie de ce que j'ai dit est incorrecte? Robert donne un exemple d'utilisation d'un autre outil pour appeler plusieurs fois cp comme je le suggère. Il existe de nombreuses solutions possibles qui impliquent l'utilisation d'autres outils ou constructions pour ce faire, mais le PO a indiqué qu'il était déjà conscient que c'était possible.
moonshadow
2
Malheureusement, ce serait génial pour cp (et scp) de supporter cette fonctionnalité. Pourtant, nous pouvons utiliser le tee pour faire la séparation. superuser.com/questions/32630/…
Simon
4
@moonshadow: Bien sûr, votre réponse est correcte. Je pense que PlagueHammer veut dire que dans ce contexte, l'autre réponse est plus utile. Peut-être pourriez-vous aussi inclure quelque chose comme ça dans votre réponse?
Peaceful
585

Vous ne pouvez pas le faire cpseul, mais vous pouvez combiner cpavec xargs:

echo dir1 dir2 dir3 | xargs -n 1 cp file1

Copiera file1à dir1, dir2et dir3. xargsappellera cp3 fois pour ce faire, consultez la page de manuel pour plus xargsde détails.

Robert Gamble
la source
3
Plus d'informations sur xargs: cyberciti.biz/faq/…
Chris Bier
24
@Simon comment ça? "Vous ne pouvez pas faire cela cpseul". Le simple fait que la réponse ait tenté d'être utile en suggérant une autre façon ne signifie pas que la question n'a pas été répondue.
Nicole
3
@NickC Le demandeur a spécifié: "Je sais qu'il est possible d'utiliser une boucle for, ou de trouver. Mais est-il possible d'utiliser la commande gnu cp?" La bonne réponse est celle acceptée.
Simon
25
Stipuler que les réponses soient acceptées selon qu'elles répondent techniquement à la question serait insupportablement pédant et pas vraiment utile.
Backgammon
4
Très utile! Pour les autres débutants comme moi: vous ne pouvez pas utiliser regex avec cp, mais vous pouvez dans la première partie de cette commande (par exemple echo dir[1-3] | xargs -n 1 cp filename).
Jason
77

Les caractères génériques fonctionnent également avec le code Roberts

echo ./fs*/* | xargs -n 1 cp test 
Paul
la source
et tout le commentaire ... Par exemple, pour déplacer un fichier appartenant à root (un lien symbolique en fait) qui était sur mon bureau vers le bureau de tous les utilisateurs, j'ai d'abord dû sudo su (ne fonctionnait pas autrement) puis utilisé: echo / home / * / Bureau / | xargs -n 1 cp -av / home / myusername / Desktop / file.
David G
19

Pour autant que je puisse le voir, vous pouvez utiliser ce qui suit:

ls | xargs -n 1 cp -i file.dat

L' -ioption de cpcommande signifie qu'il vous sera demandé si vous souhaitez remplacer un fichier dans le répertoire en cours par le file.dat. Bien que ce ne soit pas une solution complètement automatique, cela a fonctionné pour moi.

Evgeny
la source
1
Bien qu'il soit bon d'avoir ajouté la -igarde, cela ne vous incitera-t-il pas à écraser chaque fichier? plutôt que de copier dans les répertoires?
Hérisson
1
@Hedgehog Eh bien, je pense que cette commande est utile quand il y a un fichier dans le répertoire et que l'on veut le copier dans les sous-répertoires du répertoire. Dans ce cas, un fichier ne peut être écrasé qu'une seule fois. Merci pour votre question!
Evgeny
2
Pour moi, il a imprimé une série de cp: overwritequestions, mais je n'ai pas eu à répondre à aucune d'entre elles, et il n'a pas écrasé les fichiers.
Evgeni Sergeev
Également imprimé une série de questions + copié dans un fichier avec le nom du répertoire avec le caractère ':' à la fin, aucune solution de travail du tout, la solution de Paul fonctionne parfaitement
jgpATs2w
19

J'utiliser catet teesur la base des réponses que j'ai vu à /superuser/32630/parallel-file-copy-from-single-source-to-multiple-targets au lieu de cp.

Par exemple:

cat inputfile | tee outfile1 outfile2 > /dev/null
deterb
la source
1
Un test superficiel que je viens de faire montre que c'est le meilleur interprète si vos destinations sont des lecteurs physiques différents (en conservant deux copies physiques d'une base de fichiers comme la vidéo source pour un film numérique).
curieux
1
Si vous utilisez bash 3.0 ou supérieur, vous pouvez utiliser les plages comme suit:cat <inputfile> | tee /path-to-files/outfile{1..4} > /dev/null
Samuel
tee < inputfile outfile1 outfile2 > /dev/nullest également un modèle utile comme le montre la réponse de Taywee. Notez l'utilisation de io-redirection avec '<' afin que la tuyauterie de cat ne soit pas nécessaire.
Alex Telon
10

Ces réponses semblent toutes plus compliquées que l'évidence:

for i in /foo /bar; do cp "$file1" "$i"; done
Waxrat
la source
un élégant et fonctionnel, pour le faire pour tous les répertoires du répertoire courant, on peut utiliserfor d in */ ; do cp $file "$i" done
FantomX1
9

ls -db di*/subdir | xargs -n 1 cp File

-bdans le cas où il y a un espace dans le nom du répertoire sinon il sera cassé comme un élément différent par xargs, a eu ce problème avec la version echo

thAAAnos
la source
6

Ne pas utiliser cp en soi, mais ...

Cela m'est venu dans le contexte de la copie de nombreuses séquences Gopro d'une carte SD (lente) vers trois lecteurs USB (lents). Je ne voulais lire les données qu'une seule fois, car cela prenait une éternité. Et je le voulais récursif.

$ tar cf - src | tee >( cd dest1 ; tar xf - ) >( cd dest2 ; tar xf - ) | ( cd dest3 ; tar xf - )

(Et vous pouvez ajouter plus de ces sections> () si vous voulez plus de sorties.)

Je n'ai pas évalué cela, mais c'est certainement beaucoup plus rapide que cp-in-a-loop (ou un tas d'invocations cp parallèles).

oggust
la source
5

Pour utiliser la copie avec xargsdes répertoires à l'aide de caractères génériques sur Mac OS, la seule solution qui a fonctionné pour moi avec des espaces dans le nom du répertoire est:

find ./fs*/* -type d -print0 | xargs -0 -n 1 cp test 

Où se testtrouve le fichier à copier
Et ./fs*/*les répertoires à copier

Le problème est que xargs voit les espaces comme un nouvel argument, les solutions pour changer le caractère de délimitation en utilisant -dou -Ene fonctionnent malheureusement pas correctement sous Mac OS.

MegaCookie
la source
4

Si vous voulez le faire sans commande fourchue:

tee <inputfile file2 file3 file4 ... >/dev/null

Taywee
la source
2

Essentiellement équivalent à la réponse xargs, mais au cas où vous souhaiteriez une exécution parallèle:

parallel -q cp file1 ::: /foo/ /bar/

Ainsi, par exemple, pour copier file1 dans tous les sous-répertoires du dossier actuel (y compris la récursivité):

parallel -q cp file1 ::: `find -mindepth 1 -type d`

NB: Cela ne transmet probablement aucun gain de vitesse notable pour des cas d'utilisation très spécifiques, par exemple si chaque répertoire cible est un disque distinct.

Il est également fonctionnellement similaire à l'argument «-P» pour xargs.

alainv
la source
0

Non tu ne peux pas.

J'ai découvert à plusieurs reprises que je pouvais utiliser cette fonctionnalité, j'ai donc créé mon propre outil pour le faire pour moi.

http://github.com/ddavison/branch

assez simple -
branch myfile dir1 dir2 dir3

ddavison
la source
Il y a souvent des scénarios où j'écrirais mon propre script, mais j'ai tendance à utiliser tellement de machines de nos jours que les garder toutes synchronisées semble être un problème majeur. Si seulement il y avait un moyen de monter un répertoire web cloud /epar exemple, juste une fois sur chaque machine, alors je pourrais écrire mes propres outils électriques et les garder pour toujours.
Evgeni Sergeev
0
ls -d */ | xargs -iA cp file.txt A
Sj Lee
la source
1
Que diriez-vous d'un peu d'explication?
min
Cela fonctionne réellement, mais une explication aurait été formidable
Ælex
0

Supposons que vous souhaitiez copier fileName.txtdans tous les sous-répertoires du répertoire de travail actuel.

  1. Obtenez tous les noms de sous-répertoires lset enregistrez-les dans un fichier temporaire, par exemple,allFolders.txt

    ls > allFolders.txt
  2. Imprimez la liste et passez-la à la commande xargs.

    cat allFolders.txt | xargs -n 1 cp fileName.txt
Devendra Lattu
la source
0

Une autre façon consiste à utiliser chat et tee comme suit:

cat <source file> | tee <destination file 1> | tee <destination file 2> [...] > <last destination file>

Je pense que ce serait assez inefficace, car le travail serait divisé en plusieurs processus (un par destination) et le disque dur écrirait plusieurs fichiers à la fois sur différentes parties du plateau. Cependant, si vous vouliez écrire un fichier sur plusieurs lecteurs différents, cette méthode serait probablement assez efficace (car toutes les copies pourraient se produire simultanément).

jww
la source
0

Utilisation d'un script bash

DESTINATIONPATH[0]="xxx/yyy"
DESTINATIONPATH[1]="aaa/bbb"
                ..
DESTINATIONPATH[5]="MainLine/USER"
NumberOfDestinations=6

for (( i=0; i<NumberOfDestinations; i++))
    do
        cp  SourcePath/fileName.ext ${DESTINATIONPATH[$i]}

    done
exit
Patrick Manley
la source
Je lui ai donné un downvote. La question demandait spécifiquement une solution sans boucle.
Alex Telon
-1

si vous souhaitez copier plusieurs dossiers dans plusieurs dossiers, vous pouvez faire quelque chose comme ceci:

echo dir1 dir2 dir3 | xargs -n 1 cp -r / path / toyourdir / {subdir1, subdir2, subdir3}

Isaac
la source
-1

Si tous vos répertoires cibles correspondent à une expression de chemin d'accès - comme ils sont tous des sous-répertoires de path/to- alors utilisez simplement finden combinaison avec cpcomme ceci:

find ./path/to/* -type d -exec cp [file name] {} \;

C'est tout.

Mig82
la source
Je lui ai donné un downvote. La question demandait spécifiquement une solution non trouvée.
Alex Telon
Merci d'être si minutieux @AlexTelon. Je suppose que j'ai raté ce morceau. J'espère que vous étiez également cohérent et avez donné un vote négatif à toutes les autres réponses en utilisant finddans le fil.
Mig82
-2

Si vous devez être précis sur les dossiers dans lesquels copier le fichier, vous pouvez combiner la recherche avec un ou plusieurs greps. Par exemple, pour remplacer toute occurrence de favicon.ico dans n'importe quel sous-dossier, vous pouvez utiliser:

find . | grep favicon\.ico | xargs -n 1 cp -f /root/favicon.ico
Kristofer
la source
-3

Cela copiera dans les sous-répertoires immédiats, si vous voulez aller plus loin, ajustez le -maxdepthparamètre.

find . -mindepth 1 -maxdepth 1 -type d| xargs -n 1 cp -i index.html

Si vous ne souhaitez pas copier dans tous les répertoires, nous espérons que vous pourrez filtrer les répertoires qui ne vous intéressent pas. Exemple de copie dans tous les dossiers commençant par a

find . -mindepth 1 -maxdepth 1 -type d| grep \/a |xargs -n 1 cp -i index.html

Si vous copiez vers un ensemble de répertoires arbitraire / disjoint, vous aurez besoin de la suggestion de Robert Gamble.

Hérisson
la source
-3

J'aime copier un fichier dans plusieurs répertoires en tant que tel: cp file1 /foo/; cp file1 /bar/; cp file1 /foo2/; cp file1 /bar2/ Et copier un répertoire dans d'autres répertoires: cp -r dir1/ /foo/; cp -r dir1/ /bar/; cp -r dir1/ /foo2/; cp -r dir1/ /bar2/

Je sais que c'est comme émettre plusieurs commandes, mais cela fonctionne bien pour moi quand je veux taper 1 ligne et m'éloigner pendant un moment.

Stace Fauske
la source
7
Vous répondez à une question de 6 ans avec 15 autres réponses. Votre réponse doit être assez originale. Mon avis - ce n'est pas le cas.
Craig S. Anderson
-4

Par exemple, si vous êtes dans le répertoire parent de vos dossiers de destination, vous pouvez faire:

pour i en $ (ls); faire le fichier source cp $ i; terminé

Behrooz
la source
La question dit que c'est possible avec une boucle for, donc cela n'ajoute vraiment rien.
LJNielsenDk
Voté. N'essayez jamais d'analyser la sortie dels et toujours de citer des variables. for i in ./*; do cp sourcefile "$i"; done
sleblanc