So kopieren Sie eine Datei mit dem Befehl gnu cp in mehrere Verzeichnisse

210

Ist es möglich, eine einzelne Datei mit dem Befehl cp in mehrere Verzeichnisse zu kopieren?

Ich habe folgendes versucht, was nicht funktioniert hat:

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

Ich weiß, dass es möglich ist, eine for-Schleife zu verwenden oder zu finden. Aber ist es möglich, den Befehl gnu cp zu verwenden?

Tom Feiner
quelle

Antworten:

106

Nein, cpkann mehrere Quellen kopieren, wird jedoch nur an ein einzelnes Ziel kopiert. Sie müssen festlegen, dass cpmehrere Male - einmal pro Ziel - aufgerufen wird, was Sie tun möchten. Verwenden Sie, wie Sie sagen, eine Schleife oder ein anderes Werkzeug.

Mondschatten
quelle
Danke für die Antwort! Jetzt, wo ich ein bisschen mehr darüber nachdenke, wird cp ohne zusätzliche Flags (die nicht existieren) nicht wissen, was die Quelle und was das DEST-Verzeichnis ist.
Tom Feiner
10
Dies ist nicht die richtige Antwort. Bitte lesen Sie die Antwort von Robert Gamble.
PlagueHammer
23
@ Nocturne: Welcher Teil von dem, was ich gesagt habe, ist falsch? Robert gibt ein Beispiel für die Verwendung eines anderen Tools, um cp mehrmals aufzurufen, wie ich vorschlage. Es gibt viele mögliche Lösungen, bei denen andere Tools oder Konstrukte verwendet werden, aber das OP hat angegeben, dass er bereits wusste, dass dies möglich ist.
Mondschatten
2
Leider wäre es für cp (und scp) großartig, diese Funktion zu unterstützen. Dennoch können wir Tee verwenden, um den Split zu machen. superuser.com/questions/32630/…
Simon
4
@moonshadow: Natürlich ist deine Antwort richtig. Ich denke, PlagueHammer möchte sagen, dass in diesem Zusammenhang die andere Antwort nützlicher ist. Vielleicht können Sie so etwas auch in Ihre Antwort aufnehmen?
Friedlicher
585

Sie können dies nicht cpalleine tun, aber Sie können kombinieren cpmit xargs:

echo dir1 dir2 dir3 | xargs -n 1 cp file1

Kopiert file1zu dir1, dir2und dir3. xargsIch werde cp3 Mal anrufen , um dies zu tun. Weitere xargsInformationen finden Sie in der Manpage .

Robert Gamble
quelle
3
Weitere Informationen zu xargs: cyberciti.biz/faq/…
Chris Bier
24
@ Simon wie so? "Sie können dies nicht cpalleine tun " Nur weil die Antwort versucht hat, hilfreich zu sein, indem sie einen anderen Weg vorschlägt, heißt das nicht, dass die Frage nicht beantwortet wurde.
Nicole
3
@NickC Der Fragesteller gab an: "Ich weiß, dass es möglich ist, eine for-Schleife zu verwenden oder zu finden. Aber ist es möglich, den Befehl gnu cp zu verwenden?" Die gute Antwort ist die akzeptierte.
Simon
25
Die Annahme, dass Antworten akzeptiert werden, basierend darauf, ob sie die Frage technisch beantworten, wäre unerträglich pedantisch und nicht wirklich nützlich.
Backgammon
4
Sehr hilfreich! Für andere Anfänger wie mich: Sie können Regex nicht mit cp verwenden, aber Sie können im ersten Teil dieses Befehls (z echo dir[1-3] | xargs -n 1 cp filename. B. ).
Jason
77

Platzhalter funktionieren auch mit Roberts-Code

echo ./fs*/* | xargs -n 1 cp test 
Paul
quelle
und der ganze Kommentar ... Um beispielsweise eine Root-Datei (eigentlich ein Symlink), die sich auf meinem Desktop befand, auf den Desktop aller Benutzer zu verschieben, musste ich zuerst sudo su (funktionierte sonst nicht) und dann Folgendes verwenden: echo / home / * / Desktop / | xargs -n 1 cp -av / home / myusername / Desktop / file.
David G
19

Soweit ich es sehen kann, können Sie Folgendes verwenden:

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

Die -iBefehlsoption cpbedeutet, dass Sie gefragt werden, ob Sie eine Datei im aktuellen Verzeichnis mit dem überschreiben möchten file.dat. Obwohl es keine vollautomatische Lösung ist, hat es für mich geklappt.

Evgeny
quelle
1
Es ist zwar gut, den -iGuard hinzugefügt zu haben , aber fordert Sie das nicht dazu auf, jede Datei zu überschreiben? anstatt in die Verzeichnisse zu kopieren?
Igel
1
@ Hedgehog Nun, ich denke, dass dieser Befehl nützlich ist, wenn sich eine Datei im Verzeichnis befindet und man sie in Unterverzeichnisse des Verzeichnisses kopieren möchte. In diesem Fall kann eine Datei nur einmal überschrieben werden. Danke für deine Frage!
Evgeny
2
Für mich wurden eine Reihe von cp: overwriteFragen gedruckt , aber ich musste keine beantworten, und die Dateien wurden nicht überschrieben.
Evgeni Sergeev
Außerdem wurde eine Reihe von Fragen gedruckt + in die Datei mit dem Namen dir mit dem Zeichen ':' am Ende kopiert, überhaupt keine funktionierende Lösung, Pauls Lösung funktioniert perfekt
jgpATs2w
19

Ich würde catund teebasierend auf den Antworten, die ich unter /superuser/32630/parallel-file-copy-from-single-source-to-multiple-targets gesehen habe, anstelle von cp.

Beispielsweise:

cat inputfile | tee outfile1 outfile2 > /dev/null
abschrecken
quelle
1
Ein flüchtiger Test, den ich gerade durchgeführt habe, zeigt, dass dies die beste Leistung erbringt, wenn Ihre Ziele unterschiedliche physische Laufwerke sind (zwei physische Kopien einer Dateibasis wie Quellvideo für einen digitalen Film).
neugieriger
1
Wenn Sie Bash 3.0 oder höher verwenden, können Sie Bereiche wie folgt verwenden:cat <inputfile> | tee /path-to-files/outfile{1..4} > /dev/null
Samuel
tee < inputfile outfile1 outfile2 > /dev/nullist auch ein nützliches Muster, wie Taywees Antwort zeigt. Beachten Sie die Verwendung der Io-Umleitung mit '<', damit keine Rohrleitungen von cat benötigt werden.
Alex Telon
10

Diese Antworten scheinen alle komplizierter als das Offensichtliche:

for i in /foo /bar; do cp "$file1" "$i"; done
Waxrat
quelle
eine elegante und funktionierende, um es für alle Verzeichnisse im aktuellen Verzeichnis zu tun, kann man verwendenfor d in */ ; do cp $file "$i" done
FantomX1
9

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

-bFalls der Verzeichnisname ein Leerzeichen enthält , wird er von xargs als anderes Element beschädigt. Hatte dieses Problem mit der Echo-Version

thAAAnos
quelle
6

Nicht mit cp per se, aber ...

Dies kam für mich im Zusammenhang mit dem Kopieren vieler Gopro-Aufnahmen von einer (langsamen) SD-Karte auf drei (langsame) USB-Laufwerke. Ich wollte die Daten nur einmal lesen, weil es ewig gedauert hat. Und ich wollte es rekursiv.

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

(Und Sie können weitere dieser> () Abschnitte hinzufügen, wenn Sie mehr Ausgaben wünschen.)

Ich habe das nicht bewertet, aber es ist definitiv viel schneller als cp-in-a-loop (oder eine Reihe paralleler cp-Aufrufe).

oggust
quelle
5

Für das Kopieren xargsin Verzeichnisse mit Platzhaltern unter Mac OS ist die einzige Lösung, die für mich mit Leerzeichen im Verzeichnisnamen funktioniert hat, folgende:

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

Wo testist die Datei zu kopieren
und./fs*/* Verzeichnisse zu kopieren

Das Problem ist, dass xargs Leerzeichen als neues Argument ansieht, die Lösungen zum Ändern des Trennzeichens unter Verwendung von -doder unter -EMac OS leider nicht richtig funktioniert.

MegaCookie
quelle
4

Wenn Sie dies ohne einen gegabelten Befehl tun möchten:

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

Taywee
quelle
2

Entspricht im Wesentlichen der Antwort von xargs, aber falls Sie eine parallele Ausführung wünschen:

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

So kopieren Sie beispielsweise Datei1 in alle Unterverzeichnisse des aktuellen Ordners (einschließlich Rekursion):

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

NB: Dies führt wahrscheinlich nur zu spürbaren Geschwindigkeitsgewinnen für ganz bestimmte Anwendungsfälle, z. B. wenn jedes Zielverzeichnis eine eigene Festplatte ist.

Es ähnelt auch funktional dem Argument '-P' für xargs.

alainv
quelle
0

Nein, du kannst nicht.

Ich habe mehrfach festgestellt, dass ich diese Funktionalität nutzen kann, also habe ich mein eigenes Tool erstellt, um dies für mich zu tun.

http://github.com/ddavison/branch

ziemlich einfach -
branch myfile dir1 dir2 dir3

ddavison
quelle
Es gibt oft Szenarien, in denen ich mein eigenes solches Skript schreibe, aber ich benutze heutzutage so viele Maschinen, dass es ein großer Aufwand ist, sie alle synchron zu halten. Wenn es nur eine Möglichkeit gäbe, ein Cloud-Webverzeichnis /ebeispielsweise nur einmal auf jedem Computer zu mounten , könnte ich meine eigenen Powertools schreiben und sie für immer behalten.
Evgeni Sergeev
0
ls -d */ | xargs -iA cp file.txt A
Sj Lee
quelle
1
Wie wäre es mit einer Erklärung?
Minuten
Das funktioniert tatsächlich, aber eine Erklärung wäre großartig gewesen
Ælex
0

Angenommen, Sie möchten in fileName.txtalle Unterverzeichnisse im aktuellen Arbeitsverzeichnis kopieren .

  1. Holen Sie sich alle Namen der Unterverzeichnisse durch lsund speichern Sie sie in einer temporären Datei.allFolders.txt

    ls > allFolders.txt
  2. Drucken Sie die Liste aus und übergeben Sie sie an den Befehl xargs.

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

Eine andere Möglichkeit besteht darin, Katze und Tee wie folgt zu verwenden:

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

Ich denke, dies wäre jedoch ziemlich ineffizient, da der Job auf mehrere Prozesse aufgeteilt würde (einer pro Ziel) und die Festplatte mehrere Dateien gleichzeitig über verschiedene Teile des Plattentellers schreiben würde. Wenn Sie jedoch eine Datei auf mehrere verschiedene Laufwerke schreiben möchten, ist diese Methode wahrscheinlich ziemlich effizient (da alle Kopien gleichzeitig ausgeführt werden können).

jww
quelle
0

Verwenden eines Bash-Skripts

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
quelle
Ich habe dies abgelehnt. Die Frage stellte speziell eine Non-Loop-Lösung.
Alex Telon
-1

Wenn Sie mehrere Ordner in mehrere Ordner kopieren möchten, können Sie Folgendes tun:

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

Isaac
quelle
-1

Wenn alle Ihre Zielverzeichnisse mit einem Pfadausdruck übereinstimmen - wie sie alle Unterverzeichnisse von path/to-, verwenden Sie sie einfach findin Kombination mit folgendem cp:

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

Das ist es.

Mig82
quelle
Ich habe dies abgelehnt. Die Frage stellte speziell eine nicht gefundene Lösung.
Alex Telon
Vielen Dank, dass Sie so gründlich @AlexTelon sind. Ich glaube, ich habe das bisschen verpasst. Ich hoffe, Sie waren auch konsequent und haben jede andere Antwort, die findin thread verwendet wurde, abgelehnt.
Mig82
-2

Wenn Sie genau angeben möchten, in welche Ordner die Datei kopiert werden soll, können Sie find mit einem oder mehreren greps kombinieren. Zum Beispiel, um alle Vorkommen von favicon.ico in einem beliebigen Unterordner zu ersetzen, können Sie Folgendes verwenden:

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

Dadurch wird in die unmittelbaren Unterverzeichnisse kopiert. Wenn Sie tiefer gehen möchten, passen Sie den -maxdepthParameter an.

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

Wenn Sie nicht in alle Verzeichnisse kopieren möchten, können Sie hoffentlich die Verzeichnisse filtern, an denen Sie nicht interessiert sind. Beispiel für das Kopieren in alle Ordner, beginnend mit a

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

Wenn Sie in einen beliebigen / nicht zusammenhängenden Satz von Verzeichnissen kopieren, benötigen Sie den Vorschlag von Robert Gamble.

Igel
quelle
-3

Ich möchte eine Datei als solche in mehrere Verzeichnisse cp file1 /foo/; cp file1 /bar/; cp file1 /foo2/; cp file1 /bar2/ kopieren : Und ein Verzeichnis in andere Verzeichnisse kopieren: cp -r dir1/ /foo/; cp -r dir1/ /bar/; cp -r dir1/ /foo2/; cp -r dir1/ /bar2/

Ich weiß, dass es so ist, als würde man mehrere Befehle ausgeben, aber es funktioniert gut für mich, wenn ich eine Zeile eingeben und eine Weile weggehen möchte.

Stace Fauske
quelle
7
Sie beantworten eine 6 Jahre alte Frage mit 15 weiteren Antworten. Ihre Antwort muss ziemlich neu sein. Meine Meinung - ist es nicht.
Craig S. Anderson
-4

Wenn Sie sich beispielsweise im übergeordneten Verzeichnis Ihrer Zielordner befinden, können Sie Folgendes tun:

für i in $ (ls); do cp sourcefile $ i; getan

Behrooz
quelle
Die Frage besagt, dass es mit einer for-Schleife möglich ist, also fügt dies wirklich nichts hinzu.
LJNielsenDk
Abgestimmt. Versuchen Sie niemals, die Ausgabe von zu analysierenls , und zitieren Sie immer Variablen. for i in ./*; do cp sourcefile "$i"; done
Sleblanc