Làm thế nào để sao chép-hợp nhất hai thư mục?


112

Tôi có hai thư mục hình ảnh và hình ảnh2 với cấu trúc này trong Linux:

/images/ad  
/images/fe  
/images/foo  

... và 4000 thư mục khác

và cái khác giống như:

/images2/ad  
/images2/fe  
/images2/foo

... và 4000 thư mục khác

Mỗi thư mục này chứa hình ảnh và tên của thư mục bên dưới hình ảnh và hình ảnh2 hoàn toàn giống nhau, tuy nhiên nội dung của chúng là khác nhau. Sau đó, tôi muốn biết làm thế nào tôi có thể sao chép-hợp nhất hình ảnh của / hình ảnh2 / quảng cáo vào hình ảnh / quảng cáo, hình ảnh của / hình ảnh2 / foo vào hình ảnh / foo và vv với tất cả 4000 thư mục ..


1
các tập tin cuối có tên giống nhau trong cả hai thư mục?
Simply_Me

Không ... ví dụ trong hình ảnh / quảng cáo là 1.jpg, 2.jpg và 3.jpg. Nhưng trong hình ảnh 2 / quảng cáo là 4.jpg và 5.jpg
ssierral

4
@AmirAliAkbari, tôi không nghĩ rằng đó là một bản sao - câu hỏi khác về cơ bản là 'Liệu mv có hợp nhất không?' (trả lời: không). Câu hỏi này là về cách hợp nhất 2 hệ thống phân cấp thư mục.
maxschlepzig

Câu trả lời:


173

Đây là một công việc cho rsync . Không có lợi ích để làm điều này bằng tay với một vòng lặp shell trừ khi bạn muốn di chuyển tệp thay vì sao chép chúng.

rsync -a /path/to/source/ /path/to/destination

Trong trường hợp của bạn:

rsync -a /images2/ /images/

(Lưu ý dấu gạch chéo trên images2, nếu không nó sẽ sao chép vào /images/images2.)

Nếu hình ảnh có cùng tên tồn tại trong cả hai thư mục, lệnh trên sẽ ghi đè lên /images/SOMEPATH/SOMEFILEvới /images2/SOMEPATH/SOMEFILE. Nếu bạn muốn chỉ thay thế các tệp cũ hơn, hãy thêm tùy chọn -u. Nếu bạn muốn luôn giữ phiên bản trong /images, hãy thêm tùy chọn --ignore-existing.

Nếu bạn muốn di chuyển các tệp từ /images2, với rsync, bạn có thể chuyển tùy chọn --remove-source-files. Sau đó, rsync sao chép tất cả các tệp lần lượt và xóa từng tệp khi hoàn tất. Điều này chậm hơn rất nhiều so với việc di chuyển nếu các thư mục nguồn và đích nằm trên cùng một hệ thống tệp.


14
..add -P nếu bạn muốn thấy sự tiến bộ ..
Meetai.com

1
Tôi muốn nói thêm rằng không có lợi cho việc sử dụng một vòng lặp vỏ khó hiểu ở đây ngay cả khi bạn làm muốn di chuyển chúng thay vì sao chép chúng trong trường hợp đó chỉ cần sử dụng rsync, sau đó rm -r /images.
tự đại diện

1
Tôi cũng muốn chỉ ra rằng điều quan trọng là bao gồm các dấu gạch chéo cho mỗi thư mục . Ví dụ, nếu bạn chỉ đơn giản chạy rsync -a images images2, nó sẽ chỉ sao chép hình ảnh2 thành hình ảnh thay vì hợp nhất chúng.
Kyle Challis

1
@ s3cur3 ơi. Từ 2 đến (ngầm) 1. Điều đó không trực quan. Cảm ơn, tôi đã sửa câu trả lời của mình.
Gilles

1
@MaxCoplan số Rsync không phải là một công cụ tương tác.
Gilles

43

Sự lựa chọn tốt nhất, như đã được đăng, tất nhiên là rsync. Tuy nhiên, unison cũng sẽ là một phần mềm tuyệt vời để thực hiện công việc này. Cả hai có thể được sử dụng trong một số hệ điều hành.

Đồng bộ hóa

rsync đồng bộ hóa theo một hướng từ nguồn đến đích. Do đó, tuyên bố sau đây

rsync -avh --progress Source Destination

đồng bộ mọi thứ từ Nguồn đến Đích . Thư mục hợp nhất nằm trong Destination .

-a có nghĩa là "lưu trữ" và sao chép mọi thứ đệ quy từ nguồn đến đích bảo tồn gần như mọi thứ.

-v cho đầu ra nhiều hơn ("dài dòng").

-h cho con người đọc được.

- xuất hiện để hiển thị bao nhiêu công việc được thực hiện.

Nếu bạn muốn chỉ cập nhật các điểm đến thư mục với mới tập tin từ thư mục nguồn:

rsync -avhu --progress source destination

Đồng nhất

đồng bộ hóa đồng bộ theo cả hai hướng. Do đó, tuyên bố sau đây

unison Source Destination

đồng bộ cả hai thư mục theo cả hai hướng và cuối cùng là nguồn bằng đích. Nó giống như làm rsync hai lần từ nguồn đến định mệnh và ngược lại.

Để biết cách sử dụng nâng cao hơn, hãy xem các trang hướng dẫn hoặc các trang web sau:

  1. https://www.cis.upenn.edu/~bcpierce/unison/
  2. https://rsync.samba.org/

2
Tôi muốn đề cập rằng đường dẫn chính xác đến thư mục phải có dấu gạch chéo ở cuối rsync -avh --progress source/ destination/, nếu không thư mục nguồn sẽ được tạo trong thư mục đích, ít nhất là trong trường hợp của tôi giống như thế này.
Electroid

Điều này làm việc rất tốt cho tôi (với dấu gạch chéo trong các thư mục). Cảm ơn bạn!
Leopoldo Sanchot

5
for dir in images2/*; do mv "$dir"/* "images/$(basename "$dir")"; done

Lặp lại tất cả các nội dung của images2việc sử dụng một quả cầu mở rộng (để tránh các vấn đề với phân tích cú pháp ls) sau đó mvnội dung của các mục đó đến mục phù hợp trong images. Sử dụng basenameđể thoát khỏi hàng đầu images2từ con đường toàn cầu.


vui lòng thêm chi tiết về những gì lệnh của bạn làm để nó cũng hữu ích cho người đọc trong tương lai :)
Ramesh

1

@ inulinux12, bạn có thể sử dụng forvòng lặp một dòng sau từ dòng lệnh:

$ for dir in images2/*; do mv "$dir"/* "${dir/2/}"; done

Điều này sẽ di chuyển tất cả các tệp từ images2đến imagestrong thư mục tương ứng của họ. Lưu ý: điều này giả sử không có tệp nào có cùng tên.

Ví dụ:

Trước khi thực hiện:

$ ls -R images*
images:
ad  adfoo  fe
images/ad:
jpg.1  jpg.2
images/adfoo:
jpg.7
images/fe:
jpg.5
images2:
ad  adfoo  fe
images2/ad:
jpg.3
images2/adfoo:
jpg.6
images2/fe:
jpg.4

Sau khi thực hiện:

$ ls -R images*
images:
ad  adfoo  fe
images/ad:
jpg.1  jpg.2  jpg.3
images/adfoo:
jpg.6  jpg.7
images/fe:
jpg.4  jpg.5

3
Đừng phân tích đầu ra của ls. mywiki.wooledge.org/ParsingLs
Etan Reisner

@EtanReisner Cảm ơn bạn đã gợi ý; có vẻ kịch bản khá hẹp mặc dù đưa ra thông tin được đưa ra trong câu hỏi.
Simply_Me

2
@Simply_Me Mặc dù đúng là nó sẽ ổn, nhưng bạn thực sự không muốn nó nổ tung khi bạn gặp phải trường hợp mà bạn không tính đến. Nó có thể gây ra vấn đề thực sự xấu. Chưa kể rằng nó khá thường xuyên (như trong trường hợp này) gần như có thể thay thế một cách tầm thường với một quả cầu đơn giản. Xem câu trả lời của tôi là một ví dụ về điều đó.
Etan Reisner

@Simply_Me Các kịch bản bao gồm tên tệp có khoảng trắng, khá phổ biến đối với hình ảnh.
Gilles

@Gilles và @Etan Reisner, cảm ơn bạn đã đóng góp, tôi đánh giá cao nó! Đã cập nhật và kiểm tra câu trả lời của tôi để sử dụng thay thế chuỗi, và nó trở nên nhanh hơn so với sử dụng basenametrong tình huống cụ thể này (không cần phải gọi basenamecho điều này). Cảm ơn một lần nữa cho ý kiến ​​xây dựng.
Simply_Me
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.