Как заставить cp перезаписать каталог вместо создания другого внутри?


108

Я пытаюсь написать сценарий Bash, который перезапишет существующий каталог. У меня есть каталог, foo/и я пытаюсь заменить bar/его. Но когда я это сделаю:

cp -Rf foo/ bar/

создается новый bar/foo/каталог. Я не хочу этого. Есть два файла foo/; aи b. Также есть файлы с bar/такими же именами . Я хочу, чтобы foo/aи foo/bзаменить bar/aи bar/b.

Ответы:


123

Вы можете сделать это, используя -Tопцию в cp.
См. Страницу руководства для 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
на всякий случай, если кто-то запутается, он не будет работать с OSX cp developer.apple.com/library/mac/documentation/Darwin/Reference/…
— dnfehren

9
Неясно, что этот ответ - это то, что ищет OP, хотя приведенные выше примеры маскируют проблему ... С параметром -T файлы, которые находятся в существующей цели ( bar/), но не в источнике ( foo/), будут оставлены на месте, поэтому большинство людей не сочли бы это полной перезаписью каталога. т.е. если бы он bar/bazуже существовал, он все еще существовал бы после ...
— robo

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

2
Я не чтец мыслей ... Я не вижу дальнейших разъяснений, что искал OP, но это был ОПРЕДЕЛЕННО ответ, который я (MEEEE) искал
— Assimilater

2
на тот случай, если кто-то запутается, почему ссылка в самом популярном комментарии не работает, вот она: web.archive.org/web/20170909193852/https://developer.apple.com/…
— Sulphur,

48

Сделайте это в два этапа.

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

11
На самом деле это единственный приведенный пока пример, который гарантирует, что barон идентичен по содержанию foo, а не комбинации элементов из fooплюс других элементов, которые, возможно, уже существовали в bar. В ответе @Saurabh Meshram ниже, получившем высокую оценку, есть эта проблема.
— robo

1
Будьте особенно осторожны при использовании этого, так как он будет удалить все файлы из бара, даже скрытые.
— Elia Grady

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

1
Это не всегда жизнеспособно ... или желательно ... представьте, если fooи barявляются большими каталогами ... может быть, в них есть файлы bar, fooкоторые вы не хотите удалять. Это не следует считать реалистичным ответом, imho
— Assimilater

Хотя это сработало для меня, но не лучшее решение, так как файл может быть включен в foo /, но не в bar /, который будет удален после этого.
— Нитвит

47

Если вы хотите, чтобы 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 👍
— tangueroo

18

Используйте эту cpкоманду:

cp -Rf foo/* bar/

9
Это не удаляет файлы, которые присутствуют в bar, но не в foo.
— Ара,

5
Не понимаю, что вы имеете в виду. Почему cpкоманда должна удалять файл из источника?
— анубхава 01

Насколько я понимаю, когда вы «перезаписываете существующий каталог» другим, в конце перезаписываемый каталог должен быть копией другого. Т.е. в конце bar должна быть копия foo, как в случае с ответом @ jonathan-wheeler, но если у вас был файл bar / c и нет foo / c, тогда bar / c не удаляется. Кстати, я только что заметил, что это не относится и к ответу Саураба Мешрама.
— Ара

Может быть, мы не согласны с тем, что означает перезапись, для меня это в основном замена, а вы могли иметь в виду мегре? Трудно сказать, что именно хочет OP, потому что она упомянула только 2 файла, которые находятся в foo и bar.
— Ara

Этот синтаксис также игнорирует скрытые файлы точек. Большое количество также может взорвать глобус.
— xpusostomos

13

Следующая команда обеспечивает включение в копию точечных файлов (скрытых файлов):

$ cp -Rf foo/. bar

1
Это правда? Смотрится необычно.
— Mateng

2
@Mateng Я только что проверил - да, это правда.
— Матмарбон

1
.означает все файлы в каталоге. Итак, естественно, будут включены скрытые файлы.
— Джасприт Сингх

На самом деле это довольно изящно. Вы также можете использовать команду cp -RTf foo bar в Linux.
— xpusostomos

6

Очень похоже на @Jonathan Wheeler:

Если не хотите запоминать, но не переписывать bar:

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

!$ отображает последний аргумент вашей предыдущей команды.


5
Совет по поводу! $ Потрясающий!
— Лукас Морган


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