Как заставить 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
Совет по поводу! $ Потрясающий!
Лукас Морган
0

это должно решить вашу проблему.

\cp -rf foo/* bar/
али
источник
-1

Операция, которую вы определили, является «слиянием», и вы не можете этого сделать cp. Однако, если вы не ищете слияния и можете потерять папку, barвы можете просто rm -rf barудалить папку, а затем mv foo barпереименовать ее. Это не займет много времени, поскольку обе операции выполняются указателями файлов, а не содержимым файла.

Ати
источник
-2

Попробуйте использовать эту команду, состоящую из двух шагов:

rm -rf bar && cp -r foo bar
Яхор М
источник