Як змусити "cp" перезаписати каталог, а не створювати інший всередині?


107

Я намагаюся написати сценарій Bash, який замінить існуючий каталог. У мене є каталог, foo/і я намагаюся його перезаписати bar/. Але коли я це роблю:

cp -Rf foo/ bar/

створюється новий bar/foo/каталог. Я цього не хочу. Є два файли foo/; aі b. Також є файли з однаковими іменами bar/. Я хочу, щоб foo/aі foo/bзамінити bar/aі bar/b.

Відповіді:


122

Це можна зробити за допомогою -Tопції в cp.
Див. Сторінку Man для cp.

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

Отже, згідно з вашим прикладом, наступна структура файлів.

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

Ви можете бачити чітку різницю, коли використовуєте -vдля Verbose.
Коли ви використовуєте лише -Rваріант.

$ 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

Використовуючи опцію, -Tвона перезаписує вміст, обробляючи призначення як звичайний файл, а не каталог .

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

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

Це повинно вирішити вашу проблему.


22
на всякий випадок, коли хтось за це
зіткнеться,

9
Незрозуміло, що ця відповідь - це те, що шукає ОП, хоча наведені вище приклади маскують проблему ... За допомогою параметра -T файли, які знаходяться в існуючій цілі ( bar/), але не в джерелі ( foo/), залишаться на місці, тому це не те, що більшість людей вважають повним перезаписом каталогу. тобто. якби вона bar/bazвже існувала, вона все одно існувала б і після ...
робо

1
Ця відповідь відповідає на питання op, але не стосується випадку, якщо призначення вже існує, і ви хочете видалити вміст, який він містить, але вихідний каталог цього не робить. Це не очікувана поведінка копіювання файлів з одного місця в інше. Він переписує лише цільові речі, які також є у джерелі, він не торкається нічого, що не перебуває у джерелі. Ви можете очистити цільову папку, попередньо скориставшись командою для цього:rm -rf bar/* && cp -TRv foo/ bar/
theferrit32

1
Я не телепат ... Я не бачу в подальшому роз'ясненні , що ОП шукав, але це ТОЧНО відповідь , що я (Meeee) шукав
Assimilater

2
на всякий випадок, коли хтось заткнеться, чому посилання в найбільш актуальному коментарі не працює, ось він: web.archive.org/web/20170909193852/https://developer.apple.com/…
Сірка

48

Зробіть це в два етапи.

rm -r bar/
cp -r foo/ bar/

11
Це насправді єдиний приклад, наведений на даний момент, який забезпечить barідентичність за змістом foo, а не комбінацію предметів з fooплюс інші предмети, які, можливо, вже існували в bar. Ця проблема є високооціненою відповіддю @Saurabh Meshram нижче.
робо

1
Будьте особливо обережні при використанні цього, так як він буде видалити всі файли з бару, навіть приховані.
Елія Грейді

mac osx: rm -rf bar/; cp -r foo/ !$
Майкл Діммітт

1
Це не завжди життєздатне ... або по бажанню ... уявіть собі , якщо fooі barвеликі каталоги ... можливо є файли bar, які не в fooтому , що ви не хочете , щоб видалити. Це не слід розглядати як реалістичний відповідь имхо
Assimilater

Хоча для мене це працювало, але не найкраще рішення, оскільки тут може бути файл, включений у foo /, але не в смужку /, який буде видалений після цього.
Nitwit

46

Якщо ви хочете, щоб bar/кінці були ідентичними foo/, використовуйте rsyncзамість цього:

rsync -a --delete foo/ bar/

Якщо лише кілька речей змінилося, це виконає набагато швидше, ніж видалення та повторне копіювання всього каталогу.

  • -aє «архів режиму», який копіює файли точно в foo/доbar/
  • --deleteтакож видаляє зайві файли, не входячи foo/з них bar/, забезпечуючи bar/однакові кінці
  • Якщо ви хочете побачити, що це робить, додайте -vhдля досліду і читати людину
  • Примітка: слеш після fooпотрібно, в іншому випадку rsyncбуде копіювати foo/в , bar/foo/а не перезаписувати bar/себе.
    • (Slashes після каталогів в Rsync плутає, якщо вам цікаво, ось совок Вони кажуть Rsync , щоб звернутися до. Змісту каталогу, а не з каталогу самих так , щоб перезаписати з. Змісту в foo/на утримання bar/, ми використовуйте косу рису обох. Це заплутано, тому що вона не буде працювати, як очікувалося, з косою рисою на жодному з них ; rsync підлістю завжди трактує шлях до пункту призначення так, ніби він має косу рису, хоча він шанує відсутність косої риски в джерелі шлях. Таким чином , нам потрібно слеш на шляху джерела, щоб він відповідав слеш автовизначення додаються на шляху призначення, якщо ми хочемо , щоб скопіювати вміст з foo/в bar/, а не з каталогуfoo/сама посадка в bar/як bar/foo.)

rsync є дуже потужним і корисним, якщо вам цікаво роздивитися, що ще може зробити (наприклад, копіювання через ssh).


1
Ця відповідь подобається кращому cp -Tваріанту, оскільки він також працює на macosx 👍
Languageroo

18

Використовуйте цю cpкоманду:

cp -Rf foo/* bar/

9
Це не видаляє файли, які є у рядку, але не у foo.
Ара

5
Не знаю, що ти маєш на увазі під цим. Чому cpкоманда повинна видаляти файл з джерела?
anubhava

Моє розуміння полягало в тому, що коли ви 'перезаписуєте існуючий каталог' з іншим, в кінці перезаписаний каталог повинен бути копією іншого. Тобто в кінці рядка має бути копія foo, як це стосується @ jonathan-wheeler відповіді, але якщо у вас був рядок файлів / c, а foo / c, то bar / c не видаляється. Щодо сторони, я щойно помітив, що це не так і у відповіді Саурабх Мешрам.
Ара

Можливо, ми не згодні з тим, що означає перезапис, для мене це в основному замінити, тоді як ви могли мати на увазі мегре? Важко сказати, чого саме хоче "ОП", оскільки вона згадала лише два файли, які знаходяться як у foo, так і в смузі.
Ара

Цей синтаксис також ігнорує приховані точкові файли. Велика кількість також може підірвати глобус.
xpusostomos

13

Наступна команда гарантує, що в копію будуть включені точкові файли (приховані файли):

$ cp -Rf foo/. bar

1
Це правда? Виглядає незвично.
Матенг

2
@Mateng Я щойно це перевірив - так, це правда.
Матмарбон

1
.означає всі файли в каталозі. Таким чином, природно, приховані файли будуть включені.
Jaspreet Singh

Це дуже акуратно насправді. Ви також можете зробити "cp -RTf foo bar" в Linux.
xpusostomos

5

Дуже схожий на @Jonathan Wheeler:

Якщо ви не хочете згадувати, але не переписувати bar:

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

!$ відображає останній аргумент попередньої команди.


4
Порада про! $ Приголомшлива!
Лукас Морган

0

це повинно вирішити вашу проблему.

\cp -rf foo/* bar/

-1

Означена вами операція - це "злиття", і ви не можете цього зробити cp. Однак, якщо ви не шукаєте злиття і нормально втратити папку, barви можете просто rm -rf barвидалити папку, а потім mv foo barперейменувати її. Це не займе часу, оскільки обидві операції виконуються за допомогою покажчиків файлів, а не вмісту файлів.


-2

Спробуйте скористатися цією командою, що складається з двох кроків:

rm -rf bar && cp -r foo bar
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.