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.

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.


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/

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).


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/

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

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.


4
Wskazówka dotycząca! $ Jest niesamowita!
— Lucas Morgan

0

to powinno rozwiązać twój problem.

\cp -rf foo/* bar/

-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.


-2

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

rm -rf bar && cp -r foo bar
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.