Jak zmusić „cp” do nadpisania katalogu zamiast tworzenia w nim innego?

107

Próbuję napisać skrypt Bash, który nadpisze istniejący katalog. Mam katalog foo/i próbuję go nadpisać bar/. Ale kiedy to robię:

cp -Rf foo/ bar/

bar/foo/tworzony jest nowy katalog. Nie chcę tego. W programie są dwa pliki foo/; ai b. Istnieją również pliki o takich samych nazwach bar/. Chcę foo/ai foo/bwymienić bar/ai bar/b.

saketrp
źródło

Odpowiedzi:

122

Możesz to zrobić za pomocą -Topcji w cp.
Zobacz stronę podręcznika dla cp.

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

Tak więc, jak na twoim przykładzie, poniżej przedstawiono strukturę plików.

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

Możesz zobaczyć wyraźną różnicę, gdy używasz funkcji -vVerbose.
Kiedy używasz tylko -Ropcji.

$ 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

Kiedy używasz tej opcji -T, nadpisuje zawartość, traktując miejsce docelowe jak zwykły plik, a nie katalog .

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

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

To powinno rozwiązać twój problem.

Saurabh Meshram
źródło
22
na wypadek, gdyby ktoś się przez to potknął, nie będzie działać z OSX cp developer.apple.com/library/mac/documentation/Darwin/Reference/ ...
dnfehren
9
Nie jest jasne, czy ta odpowiedź jest tym, czego szuka OP, chociaż przykłady podane powyżej maskują problem ... Z opcją -T, pliki, które są w istniejącym miejscu docelowym ( bar/), ale nie w źródle ( foo/), zostaną pozostawione na miejscu, więc większość ludzi nie uważa tego za całkowite nadpisanie katalogu. to znaczy. gdyby bar/bazjuż istniał, nadal istniałby później ...
robo
1
Ta odpowiedź odpowiada na pytanie op, ale nie dotyczy przypadku, gdy miejsce docelowe już istnieje i chcesz usunąć zawartość, która zawiera, ale katalog źródłowy nie. Nie jest to oczekiwane zachowanie w przypadku kopiowania plików z jednego miejsca do drugiego. Nadpisuje tylko elementy docelowe, które są również w źródle, nie dotyka niczego w celu, czego nie ma w źródle. Możesz wyczyścić folder docelowy, poprzedzając polecenie, aby to zrobić:rm -rf bar/* && cp -TRv foo/ bar/
theferrit32
1
Nie jestem czytelnikiem w myślach ... Nie widzę dalszych wyjaśnień, czego szukał OP, ale była to ZDECYDOWANIE odpowiedź, której szukałem (MEEEE)
Assimilater
2
na wypadek, gdyby ktoś się potknął, dlaczego link w najczęściej ocenianym komentarzu nie działa, oto on: web.archive.org/web/20170909193852/https://developer.apple.com/…
Siarka
48

Zrób to w dwóch krokach.

rm -r bar/
cp -r foo/ bar/
Jonathan Wheeler
źródło
11
Jest to właściwie jedyny podany do tej pory przykład, który zapewni baridentyczną zawartość foo, a nie kombinację elementów z fooi innych elementów, które mogły już istnieć w bar. Bardzo pozytywna odpowiedź od @Saurabh Meshram poniżej przedstawia ten problem.
robo
1
Zachowaj szczególną ostrożność, ponieważ spowoduje to usunięcie wszystkich plików z paska, nawet tych ukrytych.
Elia Grady
mac osx: rm -rf bar/; cp -r foo/ !$
Michael Dimmitt
1
To nie zawsze jest opłacalne ... lub pożądane ... wyobraźcie sobie, fooi barto duże katalogi ... może są pliki bar, które nie są w footo, że nie chcą, aby usunąć. Nie należy tego uważać za realistyczną odpowiedź imho
Assimilater
Chociaż zadziałało dla mnie, ale nie jest najlepszym rozwiązaniem, ponieważ może istnieć plik zawarty w foo / ale nie w bar /, który zostanie usunięty po wykonaniu tej czynności.
Nitwit
46

Jeśli chcesz mieć pewność, że bar/kończy się identycznie foo/, użyj rsynczamiast tego:

rsync -a --delete foo/ bar/

Jeśli zmieniło się tylko kilka rzeczy, będzie to działać znacznie szybciej niż usuwanie i ponowne kopiowanie całego katalogu.

  • -ajest „trybem archiwum”, który wiernie kopiuje pliki foo/dobar/
  • --deleteusuwa niektóre pliki nie foo/z bar/tak dobrze, zapewniającbar/ kończy się identyczne
  • Jeśli chcesz zobaczyć, co robi, dodaj -vh aby były szczegółowe i czytelne dla człowieka
  • Uwaga: po ukośnik foojest wymagane, w przeciwnym razie rsynczostanie skopiowana foo/do bar/foo/zamiast nadpisywania bar/siebie.
    • (Ukośniki po katalogach w rsync są mylące; jeśli jesteś zainteresowany, oto podsumowanie. Mówią rsync, aby odnosił się do zawartości katalogu, a nie do samego katalogu Więc nadpisać z. Zawartości z foo/na treść bar/, mamy użyj ukośnika na obu. Jest to mylące, ponieważ nie będzie działać zgodnie z oczekiwaniami z ukośnikiem na żadnym z nich ; rsync podstępnie zawsze interpretuje ścieżkę docelową tak, jakby miała ukośnik, mimo że honoruje brak ukośnika w źródle ścieżka. Więc musimy ukośnik na ścieżce źródłowej, aby dopasować automatycznie dodany ukośnik na ścieżce docelowej, jeśli chcemy, aby skopiować zawartość zfoo/ dobar/ , zamiast katalogufoo/ląduje wbar/jak bar/foo.)

rsync jest bardzo potężny i przydatny, jeśli jesteś ciekawy, co jeszcze może zrobić (na przykład kopiowanie przez ssh).

Tom Potter
źródło
1
Podoba mi się ta odpowiedź lepsza niż cp -Topcja, bo działa też na macosx 👍
tongueroo
18

Użyj tego cppolecenia:

cp -Rf foo/* bar/
anubhava
źródło
9
Nie usuwa to plików, które są obecne w pasku, ale nie w foo.
Ara
5
Nie wiem, co przez to rozumiesz. Dlaczego cppolecenie powinno usuwać plik ze źródła?
anubhava
Zrozumiałem, że kiedy „nadpisujesz istniejący katalog” innym, na końcu nadpisany katalog powinien być kopią innego. Tzn. Na pasku końcowym powinna znajdować się kopia foo, tak jak w przypadku odpowiedzi @ jonathan-wheeler, ale jeśli masz plik bar / c i nie ma foo / c, to bar / c nie zostanie usunięty. Na marginesie, właśnie zauważyłem, że tak nie jest w przypadku odpowiedzi Saurabh Meshram.
Ara
Może nie zgadzamy się co do tego, co oznacza nadpisywanie, dla mnie jest to w zasadzie zastąpienie, podczas gdy możesz mieć na myśli megre? Trudno powiedzieć, czego dokładnie chce OP, ponieważ wspomniała tylko o 2 plikach, które znajdują się zarówno w foo, jak i bar.
Ara
Ta składnia ignoruje również ukryte pliki z kropkami. Duża liczba może również wysadzić glob.
xpusostomos
13

Następujące polecenie zapewnia, że ​​dotfiles (pliki ukryte) są uwzględnione w kopii:

$ cp -Rf foo/. bar
Majowe Oakes
źródło
1
Czy to prawda? Wygląda niecodziennie.
Mateng
2
@Mateng Właśnie to przetestowałem - tak, to prawda.
Matmarbon,
1
.oznacza wszystkie pliki w katalogu. Więc oczywiście ukryte pliki zostaną uwzględnione.
Jaspreet Singh
Właściwie to całkiem fajne. W Linuksie możesz także wykonać "cp -RTf foo bar".
xpusostomos
5

Bardzo podobny do @Jonathan Wheeler:

Jeśli nie chcesz pamiętać, ale nie przepisujesz bar:

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

!$ wyświetla ostatni argument poprzedniego polecenia.

Michael Dimmitt
źródło
4
Wskazówka dotycząca! $ Jest niesamowita!
Lucas Morgan
0

to powinno rozwiązać twój problem.

\cp -rf foo/* bar/
ali
źródło
-1

Zdefiniowana operacja to „scalanie” i nie możesz tego zrobić cp. Jeśli jednak nie chcesz scalać i zgubić folder bar, możesz po prostu rm -rf barusunąć folder, a następnie mv foo barzmienić jego nazwę. Nie zajmie to czasu, ponieważ obie operacje są wykonywane przez wskaźniki plików, a nie zawartość pliku.

Ati
źródło
-2

Spróbuj użyć tego złożonego z dwóch kroków polecenia:

rm -rf bar && cp -r foo bar
Yahor M
źródło