Bagaimana cara memaksa 'cp' untuk menimpa direktori alih-alih membuat yang lain di dalamnya?

107

Saya mencoba menulis skrip Bash yang akan menimpa direktori yang sudah ada. Saya memiliki direktori foo/dan saya mencoba menimpanya bar/. Tetapi ketika saya melakukan ini:

cp -Rf foo/ bar/

bar/foo/direktori baru dibuat. Saya tidak menginginkan itu. Ada dua file di foo/; adan b. Ada juga file dengan nama yang sama bar/. Saya ingin foo/adan foo/buntuk mengganti bar/adan bar/b.

saketrp
sumber

Jawaban:

122

Anda dapat melakukan ini menggunakan -Topsi di cp.
Lihat Halaman manual untuk cp.

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

Jadi sesuai contoh Anda, berikut ini adalah struktur file.

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

Anda dapat melihat perbedaan yang jelas saat Anda menggunakan -vVerbose.
Saat Anda menggunakan -Ropsi saja .

$ 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

Ketika Anda menggunakan opsi -Titu menimpa konten, memperlakukan tujuan seperti file biasa dan bukan direktori .

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

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

Ini seharusnya menyelesaikan masalah Anda.

Saurabh Meshram
sumber
22
kalau-kalau ada yang tersandung oleh ini, itu tidak akan bekerja dengan OSX cp developer.apple.com/library/mac/documentation/Darwin/Reference/…
dnfehren
9
Tidak jelas bahwa jawaban inilah yang dicari OP, meskipun contoh yang diberikan di atas menutupi masalahnya ... Dengan opsi -T, file yang ada di target yang sudah ada ( bar/) tetapi tidak di sumber ( foo/) akan ditinggalkan di tempatnya, jadi ini bukan apa yang dianggap kebanyakan orang sebagai penimpaan direktori secara lengkap. yaitu. jika bar/bazsudah ada, itu akan tetap ada setelah itu ...
robo
1
Jawaban ini menjawab pertanyaan op, tetapi tidak menjawab kasus jika tujuan sudah ada dan Anda ingin menghapus konten di dalamnya tetapi direktori sumber tidak. Ini bukanlah perilaku yang diharapkan dari menyalin file dari satu tempat ke tempat lain. Itu hanya menimpa hal-hal target yang juga ada di sumbernya, itu tidak menyentuh apa pun di target yang tidak ada di sumbernya. Anda dapat membersihkan folder target dengan memberikan perintah untuk melakukannya:rm -rf bar/* && cp -TRv foo/ bar/
theferrit32
1
Saya bukan pembaca pikiran ... Saya tidak melihat klarifikasi lebih lanjut apa yang dicari OP, tapi ini PASTI jawaban yang saya (MEEEE) cari
Assimilater
2
untuk berjaga-jaga jika ada yang tersandung oleh mengapa tautan di komentar yang paling banyak diberi suara positif tidak berfungsi, ini dia: web.archive.org/web/20170909193852/https://developer.apple.com/…
Sulphur
48

Lakukan dalam dua langkah.

rm -r bar/
cp -r foo/ bar/
Jonathan Wheeler
sumber
11
Ini sebenarnya satu - satunya contoh yang diberikan sejauh ini yang akan memastikan bahwa barkonten identik dengan foo, bukan kombinasi item dari fooplus item lain yang mungkin sudah ada di bar. Jawaban yang sangat disukai dari @Saurabh Meshram di bawah ini memiliki masalah ini.
robo
1
Berhati-hatilah saat menggunakannya, karena ini akan menghapus semua file dari bar, bahkan yang tersembunyi.
Elia Grady
mac osx: rm -rf bar/; cp -r foo/ !$
Michael Dimmitt
1
Hal ini tidak selalu layak ... atau yang diinginkan ... bayangkan jika foodan baradalah direktori besar ... mungkin ada file dalam baryang tidak di foobahwa Anda tidak ingin menghapus. Ini seharusnya tidak dianggap sebagai jawaban yang realistis imho
Assimilater
Meskipun berhasil untuk saya, tetapi bukan solusi terbaik karena mungkin ada file yang disertakan dalam foo / tetapi tidak di bar / yang akan dihapus setelah melakukan ini.
Nitwit
46

Jika Anda ingin memastikan bar/hasilnya sama foo/, gunakan rsyncsaja:

rsync -a --delete foo/ bar/

Jika hanya beberapa hal yang berubah, ini akan berjalan lebih cepat daripada menghapus dan menyalin ulang seluruh direktori.

  • -aadalah 'mode arsip', yang menyalin file sesuai aslinya foo/kebar/
  • --deletemenghapus file tambahan tidak foo/dari bar/juga, memastikan bar/ujung up identik
  • Jika Anda ingin melihat apa yang dilakukannya, tambahkan -vhuntuk verbose dan dapat dibaca manusia
  • Catatan: garis miring setelah foodiperlukan, jika tidak rsyncmaka akan disalin foo/ke bar/foo/daripada menimpa bar/dirinya sendiri.
    • (Garis miring setelah direktori di rsync membingungkan, jika Anda sedang tertarik, inilah sendok Mereka memberitahu rsync untuk merujuk pada. Isi dari direktori, bukan direktori itu sendiri Jadi menimpa dari. Isi dari foo/ke isi bar/, kami menggunakan garis miring pada kedua ini membingungkan karena tidak akan bekerja seperti yang diharapkan dengan sebuah garis miring pada. tidak , meskipun; rsync diam-diam selalu menafsirkan jalur tujuan seolah-olah itu memiliki garis miring, meskipun menghormati tidak adanya garis miring pada sumber jalan. Jadi kita perlu garis miring di jalan sumber untuk membuatnya sesuai dengan slash auto-ditambahkan pada jalur tujuan, jika kita ingin menyalin isi dari foo/dalam bar/, bukan direktorifoo/sendiri mendarat bar/sebagai bar/foo.)

rsync sangat kuat dan berguna, jika Anda penasaran melihat-lihat apa lagi yang bisa dilakukan (seperti menyalin ssh).

Tom Potter
sumber
1
Seperti jawaban ini lebih baik daripada cp -Topsi karena juga berfungsi pada macosx 👍
tongueroo
18

Gunakan cpperintah ini :

cp -Rf foo/* bar/
anubhava.dll
sumber
9
Ini tidak menghapus file yang ada di bar tapi tidak di foo.
Ara
5
Tidak tahu apa yang Anda maksud dengan itu. Mengapa cpperintah harus menghapus file dari sumber?
anubhava
Pemahaman saya adalah bahwa ketika Anda 'menimpa direktori yang ada' dengan yang lain, pada akhirnya direktori yang ditimpa harus merupakan salinan dari direktori yang lain. Yaitu di bilah akhir harus merupakan salinan dari foo, seperti halnya dengan jawaban @ jonathan-wheeler tetapi jika Anda memiliki bilah file / c dan tidak ada foo / c maka bar / c tidak terhapus. Di samping catatan, saya baru saja memperhatikan bahwa tidak demikian halnya dengan jawaban Saurabh Meshram.
Ara
Mungkin kita tidak setuju apa arti timpa, bagi saya itu pada dasarnya menggantikan, sementara yang Anda maksud megre? Sulit untuk mengatakan apa yang diinginkan OP karena dia hanya menyebutkan 2 file yang ada di foo dan bar.
Ara
Sintaks ini juga mengabaikan file titik tersembunyi. Sejumlah besar juga bisa meledakkan bola.
xpusostomos
13

Perintah berikut memastikan dotfiles (file tersembunyi) disertakan dalam salinan:

$ cp -Rf foo/. bar
May Oakes
sumber
1
Apakah ini benar? Tampak tidak biasa.
Mateng
2
@Mateng Saya baru saja mengujinya - ya itu benar.
Matmarbon
1
.artinya semua file dalam direktori. Jadi, tentu saja file yang tersembunyi akan disertakan.
Jaspreet Singh
Itu sebenarnya cukup rapi. Anda juga dapat melakukan "cp -RTf foo bar" di Linux.
xpusostomos
5

Sangat mirip dengan @Jonathan Wheeler:

Jika Anda tidak ingin mengingat, tetapi tidak menulis ulang bar:

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

!$ menampilkan argumen terakhir dari perintah Anda sebelumnya.

Michael Dimmitt
sumber
4
Tip tentang! $ Is awesome!
Lucas Morgan
0

ini seharusnya menyelesaikan masalah Anda.

\cp -rf foo/* bar/
ali
sumber
-1

Operasi yang Anda tetapkan adalah "gabungan" dan Anda tidak dapat melakukannya dengan cp. Namun, jika Anda tidak mencari penggabungan dan ok untuk kehilangan folder, barAnda cukup rm -rf barmenghapus folder dan kemudian mv foo barmengganti namanya. Ini tidak akan memakan waktu karena kedua operasi dilakukan oleh penunjuk file, bukan konten file.

Ati
sumber
-2

Coba gunakan perintah yang terdiri dari dua langkah ini:

rm -rf bar && cp -r foo bar
Yahor M
sumber