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.