Wie kann man 'cp' zwingen, ein Verzeichnis zu überschreiben, anstatt ein anderes darin zu erstellen?

107

Ich versuche, ein Bash-Skript zu schreiben, das ein vorhandenes Verzeichnis überschreibt. Ich habe ein Verzeichnis foo/und versuche damit zu überschreiben bar/. Aber wenn ich das mache:

cp -Rf foo/ bar/

Ein neues bar/foo/Verzeichnis wird erstellt. Das will ich nicht Es gibt zwei Dateien in foo/; aund b. Es gibt auch Dateien mit demselben Namen bar/. Ich möchte das foo/aund foo/bersetzen bar/aund bar/b.

Saketrp
quelle

Antworten:

122

Sie können dies mit der -TOption in tun cp.
Siehe Manpage für cp.

-T, --no-target-directory
    treat DEST as a normal file

Nach Ihrem Beispiel folgt die Dateistruktur.

$ tree test
test
|-- bar
|   |-- a
|   `-- b
`-- foo
    |-- a
    `-- b
2 directories, 4 files

Sie können den deutlichen Unterschied sehen, wenn Sie -vfür Verbose verwenden.
Wenn Sie nur die -ROption verwenden.

$ cp -Rv foo/ bar/
`foo/' -> `bar/foo'
`foo/b' -> `bar/foo/b'
`foo/a' -> `bar/foo/a'
 $ tree
 |-- bar
 |   |-- a
 |   |-- b
 |   `-- foo
 |       |-- a
 |       `-- b
 `-- foo
     |-- a
     `-- b
3 directories, 6 files

Wenn Sie die Option verwenden -T, wird der Inhalt überschrieben, und das Ziel wird wie eine normale Datei und nicht wie ein Verzeichnis behandelt .

$ cp -TRv foo/ bar/
`foo/b' -> `bar/b'
`foo/a' -> `bar/a'

$ tree
|-- bar
|   |-- a
|   `-- b
`-- foo
    |-- a
    `-- b
2 directories, 4 files

Dies sollte Ihr Problem lösen.

Saurabh Meshram
quelle
21
Nur für den Fall, dass jemand davon
betroffen
9
Es ist nicht klar, dass diese Antwort das ist, wonach das OP sucht, obwohl die oben angegebenen Beispiele das Problem maskieren ... Mit der Option -T bleiben Dateien bar/übrig , die sich in einem vorhandenen Ziel ( ), aber nicht in der Quelle ( foo/) befinden Dies ist also nicht das, was die meisten Leute als vollständiges Überschreiben des Verzeichnisses betrachten würden. dh. Wenn bar/bazes bereits existiert, würde es danach noch existieren ...
Robo
1
Diese Antwort beantwortet die op-Frage, geht jedoch nicht auf den Fall ein, dass das Ziel bereits vorhanden ist und Sie den darin enthaltenen Inhalt entfernen möchten, das Quellverzeichnis jedoch nicht. Dies ist kein zu erwartendes Verhalten beim Kopieren von Dateien von einem Ort zum anderen. Es überschreibt nur die Ziele, die sich auch in der Quelle befinden, und berührt nichts im Ziel, das sich nicht in der Quelle befindet. Sie können den Zielordner bereinigen, indem Sie einen Befehl rm -rf bar/* && cp -TRv foo/ bar/
voranstellen
1
Ich bin kein Gedankenleser ... Ich sehe keine weitere Klarstellung, wonach das OP gesucht hat, aber dies war definitiv die Antwort, nach der ich (MEEEE) gesucht habe
Assimilater
2
Nur für den Fall, dass jemand darüber stolpert, warum der Link im am besten bewerteten Kommentar nicht funktioniert, hier: web.archive.org/web/20170909193852/https://developer.apple.com/…
Sulphur
48

Mach es in zwei Schritten.

rm -r bar/
cp -r foo/ bar/
Jonathan Wheeler
quelle
11
Dies ist tatsächlich das einzige Beispiel, das bisher angegeben wurde, um sicherzustellen, dass der barInhalt identisch ist mit foound nicht eine Kombination aus Elementen aus foound anderen Elementen, in denen möglicherweise bereits vorhanden war bar. Die hoch gelobte Antwort von @Saurabh Meshram unten hat dieses Problem.
Robo
1
Seien Sie besonders vorsichtig diese verwenden, da es werden alle Dateien aus Leiste zu entfernen, auch ausgeblendete.
Elia Grady
Mac OSX:rm -rf bar/; cp -r foo/ !$
Michael Dimmitt
1
Dies ist nicht immer rentabel ... oder gewünscht ... vorstellen , wenn foound bargroße Verzeichnisse sind ... vielleicht gibt es Dateien in bar, die nicht in , foodass Sie nicht wollen , zu entfernen. Dies sollte nicht als realistische Antwort imho angesehen werden
Assimilater
Hat zwar für mich funktioniert, ist aber nicht die beste Lösung, da möglicherweise Dateien in foo / aber nicht in bar / enthalten sind, die danach gelöscht werden.
Nitwit
46

Wenn Sie sicherstellen möchten, dass die bar/Ergebnisse identisch sind mit foo/, verwenden Sie rsyncstattdessen:

rsync -a --delete foo/ bar/

Wenn sich nur wenige Dinge geändert haben, wird dies viel schneller ausgeführt als das Entfernen und erneute Kopieren des gesamten Verzeichnisses.

  • -aist ‚Archiv - Modus‘, die Kopien getreulich in Dateien foo/zubar/
  • --deleteentfernt zusätzliche Dateien nicht in foo/aus bar/als auch, um sicherzustellen , bar/endet identisch
  • Wenn Sie sehen möchten, was es tut, fügen Sie es -vhfür ausführlich und lesbar hinzu
  • Hinweis: Der Schrägstrich danach fooist erforderlich, andernfalls rsyncwird kopiert foo/, bar/foo/anstatt sich bar/selbst zu überschreiben .
    • (Schrägstriche nach Verzeichnissen in rsync sind verwirrend. Wenn Sie interessiert sind, finden Sie hier die Übersicht. Sie weisen rsync an, auf den Inhalt des Verzeichnisses und nicht auf das Verzeichnis selbst zu verweisen. Um also den Inhalt von foo/auf den Inhalt von zu überschreiben bar/, wir verwenden , um einen Schrägstrich auf beiden es ist verwirrend , weil es wird nicht funktionieren , wie mit einem Hieb auf erwartet. weder , obwohl, rsync sneakily immer den Zielpfad interpretiert , als ob es einen Schrägstrich hat, auch wenn es eine Abwesenheit von einem Slash auf der Quelle ehrt Pfad. Wir benötigen also einen Schrägstrich im Quellpfad, damit er mit dem automatisch hinzugefügten Schrägstrich im Zielpfad übereinstimmt, wenn wir den Inhalt von foo/in bar/und nicht in das Verzeichnis kopieren möchtenfoo/selbst landet in bar/als bar/foo.)

rsync ist sehr leistungsfähig und nützlich, wenn Sie neugierig sind und sich umschauen, was es sonst noch tun kann (z. B. Kopieren über ssh).

Tom Potter
quelle
1
Wie diese Antwort besser als die cp -TOption, weil es auch auf Macosx funktioniert tong
Tongueroo
18

Verwenden Sie diesen cpBefehl:

cp -Rf foo/* bar/
Anubhava
quelle
9
Dadurch werden keine Dateien entfernt, die in der Leiste, aber nicht in foo vorhanden sind.
Ara
5
Ich weiß nicht, was du damit meinst. Warum sollte der cpBefehl die Datei aus der Quelle entfernen?
Anubhava
Mein Verständnis war, dass, wenn Sie ein vorhandenes Verzeichnis mit einem anderen überschreiben, das überschriebene Verzeichnis am Ende eine Kopie des anderen sein sollte. Dh am Ende der Leiste sollte eine Kopie von foo sein, wie es bei der Antwort von @ jonathan-wheeler der Fall ist, aber wenn Sie eine Dateiliste / c und keine foo / c hatten, wird bar / c nicht gelöscht. Nebenbei bemerkt, ich habe gerade bemerkt, dass dies auch bei Saurabh Meshrams Antwort nicht der Fall ist.
Ara
Vielleicht sind wir uns nicht einig darüber, was Überschreiben bedeutet, für mich ist es im Grunde genommen ersetzen, während Sie vielleicht Megre gemeint haben? Es ist schwer zu sagen, was OP genau will, weil sie nur 2 Dateien erwähnt hat, die sowohl in foo als auch in bar sind.
Ara
Diese Syntax ignoriert auch versteckte Punktdateien. Eine große Anzahl kann auch den Globus in die Luft jagen.
xpusostomos
13

Der folgende Befehl stellt sicher, dass Punktedateien (versteckte Dateien) in der Kopie enthalten sind:

$ cp -Rf foo/. bar
Mai Oakes
quelle
1
Ist das wahr? Sieht ungewöhnlich aus.
Mateng
2
@Mateng Ich habe es gerade getestet - ja, es ist wahr.
Matmarbon
1
.bedeutet alle Dateien im Verzeichnis. Natürlich wären die versteckten Dateien enthalten.
Jaspreet Singh
Das ist eigentlich ziemlich ordentlich. Sie können auch "cp -RTf foo bar" unter Linux ausführen.
xpusostomos
5

Sehr ähnlich zu @Jonathan Wheeler:

Wenn Sie sich nicht erinnern, aber nicht umschreiben möchten bar:

rm -r bar/
cp -r foo/ !$

!$ Zeigt das letzte Argument Ihres vorherigen Befehls an.

Michael Dimmitt
quelle
4
Der Tipp zum! $ Ist super!
Lucas Morgan
0

Dies sollte Ihr Problem lösen.

\cp -rf foo/* bar/
ali
quelle
-1

Die von Ihnen definierte Operation ist eine "Zusammenführung", mit der Sie dies nicht tun können cp. Wenn Sie jedoch nicht nach Zusammenführen suchen und den Ordner verlieren möchten bar, können Sie den Ordner einfach rm -rf barlöschen und dann mv foo barumbenennen. Dies dauert nicht lange, da beide Vorgänge von Dateizeigern und nicht von Dateiinhalten ausgeführt werden.

Ati
quelle
-2

Versuchen Sie, diesen Befehl zu verwenden, der aus zwei Schritten besteht:

rm -rf bar && cp -r foo bar
Yahor M.
quelle