Làm thế nào để buộc 'cp' ghi đè thư mục thay vì tạo một thư mục khác bên trong?


107

Tôi đang cố gắng viết một tập lệnh Bash sẽ ghi đè lên một thư mục hiện có. Tôi có một thư mục foo/và tôi đang cố gắng ghi đè lên bar/nó. Nhưng khi tôi làm điều này:

cp -Rf foo/ bar/

một bar/foo/thư mục mới được tạo. Tôi không muốn điều đó. Có hai tệp trong foo/; ab. Có những tệp có cùng tên trong bar/. Tôi muốn foo/afoo/bđể thay thế bar/abar/b.

Câu trả lời:


122

Bạn có thể làm điều này bằng cách sử dụng -Ttùy chọn trong cp.
Xem trang Man cho cp.

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

Vì vậy, theo ví dụ của bạn, sau đây là cấu trúc tệp.

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

Bạn có thể thấy sự khác biệt rõ ràng khi bạn sử dụng -vcho Verbose.
Khi bạn chỉ sử dụng -Rtùy chọn.

$ 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

Khi bạn sử dụng tùy chọn, -Tnó sẽ ghi đè nội dung, coi đích như một tệp bình thường chứ không phải thư mục .

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

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

Điều này sẽ giải quyết vấn đề của bạn.


22
đề phòng bất kỳ ai bị vấp bởi điều này, nó sẽ không hoạt động với OSX cp developer.apple.com/library/mac/documentation/Darwin/Reference/…
dnfehren

9
Không rõ ràng rằng câu trả lời này là những gì OP đang tìm kiếm, mặc dù các ví dụ được đưa ra ở trên che giấu vấn đề ... Với tùy chọn -T, các tệp nằm trong mục tiêu hiện có ( bar/) nhưng không có trong nguồn ( foo/) sẽ bị bỏ lại tại chỗ, vì vậy đây không phải là điều mà hầu hết mọi người coi là ghi đè hoàn toàn thư mục. I E. nếu bar/baztồn tại rồi, nó vẫn sẽ tồn tại sau đó ...
robo

1
Câu trả lời này trả lời câu hỏi op, nhưng không giải quyết trường hợp nếu đích đã tồn tại và bạn muốn xóa nội dung nó chứa nhưng thư mục nguồn thì không. Đây không phải là hành vi mong đợi của việc sao chép tệp từ nơi này sang nơi khác. Nó chỉ ghi đè lên những thứ đích cũng có trong nguồn, nó không chạm vào bất cứ thứ gì trong mục tiêu không có trong nguồn. Bạn có thể làm sạch các thư mục đích bằng cách thêm vào trước một lệnh để làm điều đó:rm -rf bar/* && cp -TRv foo/ bar/
theferrit32

1
Tôi không phải là người đọc tâm trí ... Tôi không thấy rõ hơn những gì OP đang tìm kiếm, nhưng đây chính xác là câu trả lời mà tôi (MEEEE) đang tìm kiếm
Assimilater

2
đề phòng trường hợp bất kỳ ai bị vấp bởi lý do tại sao liên kết trong nhận xét được ủng hộ nhiều nhất không hoạt động, đây là: web.archive.org/web/20170909193852/https://developer.apple.com/…
Sulfur

48

Thực hiện theo hai bước.

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

11
Đây thực sự là ví dụ duy nhất được đưa ra cho đến nay sẽ đảm bảo rằng barnội dung giống hệt nhau foo, không phải là sự kết hợp của các mục từ foocộng với các mục khác có thể đã tồn tại trong đó bar. Câu trả lời được ủng hộ cao từ @Saurabh Meshram bên dưới có vấn đề này.
robo

1
Hãy hết sức cẩn thận khi sử dụng tính năng này, vì nó sẽ xóa tất cả các tệp khỏi thanh, ngay cả những tệp bị ẩn.
Elia Grady,

mac osx: rm -rf bar/; cp -r foo/ !$
Michael Dimmitt

1
Điều này không phải lúc nào cũng khả thi ... hoặc mong muốn ... hãy tưởng tượng nếu foobarlà những thư mục lớn ... có thể có những tệp trong barđó không có trong foođó mà bạn không muốn xóa. Đây không nên được coi là một câu trả lời thực tế imho
Assimilater

Mặc dù hiệu quả với tôi, nhưng không phải là giải pháp tốt nhất vì có thể có tệp được bao gồm trong foo / nhưng không phải trong thanh / sẽ bị xóa sau khi thực hiện việc này.
Nitwit

46

Nếu bạn muốn đảm bảo bar/kết thúc giống hệt nhau foo/, hãy sử dụng rsyncthay thế:

rsync -a --delete foo/ bar/

Nếu chỉ có một vài điều thay đổi, điều này sẽ thực thi nhanh hơn nhiều so với việc xóa và sao chép lại toàn bộ thư mục.

  • -alà 'chế độ lưu trữ', mà các bản sao trung thành tập tin trong foo/đểbar/
  • --deleteloại bỏ thêm file không foo/từ bar/là tốt, đảm bảo bar/đầu ra giống hệt nhau
  • Nếu bạn muốn xem nó đang làm gì, hãy thêm -vhvào cho dài và có thể đọc được
  • Lưu ý: dấu gạch chéo sau foolà bắt buộc, nếu không rsyncsẽ sao chép foo/vào bar/foo/thay vì ghi đè bar/chính nó.
    • (Dấu gạch chéo sau các thư mục trong rsync rất khó hiểu; nếu bạn quan tâm, đây là tin sốt dẻo. Họ yêu cầu rsync tham chiếu đến nội dung của thư mục, thay vì chính thư mục . Vì vậy, để ghi đè từ nội dung của foo/lên nội dung của bar/, chúng tôi sử dụng một dấu gạch chéo trên cả hai cũng rất lúng túng vì nó sẽ không làm việc như mong đợi với một dấu gạch chéo trên. không , mặc dù; rsync lén lút luôn giải thích đường dẫn đích như thể nó có một dấu gạch chéo, mặc dù nó vinh danh một sự vắng mặt của một dấu gạch chéo trên nguồn đường dẫn. Vì vậy, chúng tôi cần một dấu gạch chéo trên đường dẫn nguồn để làm cho nó khớp với dấu gạch chéo được thêm tự động trên đường dẫn đích, nếu chúng tôi muốn sao chép nội dung của foo/vào bar/, thay vì thư mụcfoo/tự hạ cánh thành bar/như bar/foo.)

rsync rất mạnh mẽ và hữu ích, nếu bạn tò mò muốn biết nó có thể làm gì khác (chẳng hạn như sao chép qua ssh).


1
Thích câu trả lời này hơn là cp -Ttùy chọn vì nó cũng hoạt động trên macosx 👍
bladeroo

18

Sử dụng cplệnh này :

cp -Rf foo/* bar/

9
Thao tác này không xóa các tệp có trong thanh nhưng không có trong foo.
Ara

5
Không biết ý của bạn là gì. Tại sao cplệnh xóa tệp khỏi nguồn?
anubhava

Sự hiểu biết của tôi là khi bạn 'ghi đè một thư mục hiện có' bằng một thư mục khác, thì cuối cùng thư mục bị ghi đè sẽ là bản sao của thư mục kia. Tức là ở thanh cuối phải là bản sao của foo, như trường hợp của câu trả lời @ jonathan-wheeler nhưng nếu bạn có thanh / c tệp và không có foo / c thì thanh / c sẽ không bị xóa. Một lưu ý nhỏ, tôi vừa nhận thấy rằng nó không đúng với câu trả lời của Saurabh Meshram.
Ara

Có thể chúng tôi không đồng ý về việc ghi đè có nghĩa là gì, đối với tôi về cơ bản nó thay thế, trong khi bạn có thể muốn nói đến megre? Thật khó để nói chính xác OP muốn gì vì cô ấy chỉ đề cập đến 2 tệp cả foo và bar.
Ara

Cú pháp này cũng bỏ qua các tệp dấu chấm ẩn. Một số lượng lớn cũng có thể làm nổ tung quả cầu.
xpusostomos

13

Lệnh sau đảm bảo tệp dotfiles (tệp ẩn) được bao gồm trong bản sao:

$ cp -Rf foo/. bar

1
Điều này có đúng không? Trông không bình thường.
Mateng

2
@Mateng Tôi vừa thử nghiệm nó - vâng, nó là sự thật.
Matmarbon

1
.có nghĩa là tất cả các tệp trong thư mục. Vì vậy, tự nhiên các tệp ẩn sẽ được bao gồm.
Jaspreet Singh

Điều đó thực sự khá gọn gàng. Bạn cũng có thể thực hiện "cp -RTf foo bar" trên Linux.
xpusostomos

5

Rất giống với @Jonathan Wheeler:

Nếu bạn không muốn nhớ, nhưng không viết lại bar:

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

!$ hiển thị đối số cuối cùng của lệnh trước đó của bạn.


4
Mẹo về! $ Thật tuyệt vời!
Lucas Morgan,

0

điều này sẽ giải quyết vấn đề của bạn.

\cp -rf foo/* bar/

-1

Thao tác bạn đã xác định là "hợp nhất" và bạn không thể làm điều đó với cp. Tuy nhiên, nếu bạn không tìm kiếm việc hợp nhất và đồng ý để mất thư mục barthì bạn có thể chỉ cần rm -rf barxóa thư mục và sau đó mv foo barđổi tên nó. Việc này sẽ không mất thời gian vì cả hai thao tác đều được thực hiện bởi con trỏ tệp, không phải nội dung tệp.


-2

Hãy thử sử dụng lệnh này bao gồm hai bước:

rm -rf bar && cp -r foo bar
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.