thư mục hợp nhất linux: rsync?


13

Tôi có hai bản sao của một thư mục

src/
dest/

Tôi muốn hợp nhất chúng, làm như sau:

Nếu một tập tin chỉ trong src, tôi muốn nó được chuyển đếndest

Nếu một tệp chỉ trong dest, tôi muốn nó bỏ qua IE một mình.

Nếu một tệp có cả hai có nội dung giống hệt nhau (IE cùng kích thước và ngày), hãy xóa khỏisrc

Nếu một tệp nằm trong cả hai và không có nội dung giống hệt nhau, hãy để lại phía sau srcđể tôi có thể hợp nhất chúng theo cách thủ công.

Chỉ một số lượng rất nhỏ các tệp (từ 0% đến 5% tổng số tệp) phải nằm trong danh mục cuối cùng này, nhưng tôi không biết cách tách phần trong cả hai và giống nhau từ cả hai, nhưng khác nhau.

Tôi đã cố gắng tìm ra cách để làm điều này với rsyncnhưng không có kết quả.

Câu trả lời:


17

Tôi chỉ thực hiện kiểm tra chức năng hạn chế, vì vậy hãy cẩn thận với lệnh này (--dry-run):

rsync -avPr --ignore-existing --remove-source-files src/ dest

Xin lưu ý dấu vết / vì điều này sẽ lặp lại vào src thay vì sao chép chính src, điều này sẽ duy trì các đường dẫn hiện có của bạn.

Bằng cách sử dụng cờ --ignore hiện có kết hợp với cờ --remove-source-files, bạn sẽ chỉ xóa các tệp từ src được đồng bộ hóa từ src sang Dest, đó là các tệp trước đây không tồn tại trong mệnh.

Để xóa các tệp không đồng bộ hóa, đó là những tệp đã tồn tại trong Dest / như trong src /, bạn có thể sử dụng:

for file in `find src/ -type f`; do diff $file `echo $file | sed 's/src/dest/'` && rm $file || echo $file; done

hoặc là

find src -type f -exec bash -c 'cmp -s "$0" "${0/#src/dest}" && rm "$0"' {} \;

nếu tên tệp có thể chứa khoảng trắng / dòng mới / Nhận xét của Gilles liên quan đến các ký tự đặc biệt, đó chắc chắn là điều cần lưu tâm và có nhiều giải pháp, cách đơn giản nhất là chuyển một -i đến rm sẽ nhắc trước khi xóa. Tuy nhiên, với điều kiện src / hoặc đường dẫn cha của nó được cung cấp để tìm, tuy nhiên, đường dẫn đủ điều kiện sẽ dẫn đến tất cả các tên tệp được xử lý đúng bởi cả hai lệnh diff và rm mà không cần trích dẫn.


sửa lỗi: lệnh đó sẽ không xóa các tệp khỏi src nếu một bản sao giống hệt đã tồn tại trong mệnh
Tok

Vâng :(. Đó là phần mà tôi thấy khó tìm ra.
David Oneill

2
Chà, tin tốt là bạn có thể giải quyết nó một cách độc lập mà không gặp nhiều rắc rối: for file in `find src/ -type f`; do diff $file `echo $file | sed 's/src/dest/'` && rm $file || echo $file; done(bạn có thể bỏ qua || echo $filenếu bạn thích, nó được bao gồm để hoàn thiện)
Tok

Tiện lợi: đó là những gì tôi cần. Chỉnh sửa câu trả lời của bạn và tôi sẽ chấp nhận nó!
David Oneill

@Tok: Lệnh của bạn sẽ bóp nghẹt tên tệp có chứa các ký tự đặc biệt (khoảng trắng \?*[, ban đầu -). Bạn cần sử dụng dấu ngoặc kép xung quanh các thay thế thay đổi , chuyển --đến các tiện ích trước tên tệp, sử dụng find … -exec …thay vì phân tích cú pháp đầu ra find. Với một rmlệnh trong hỗn hợp, đây là một công thức cho thảm họa.
Gilles 'SO- ngừng trở nên xấu xa'

6

unison là công cụ bạn đang tìm kiếm. Hãy thử unison-gtk nếu bạn thích gui. Nhưng tôi không nghĩ rằng nó sẽ xóa các tệp tương tự: unison cố gắng có cả hai thư mục giống hệt nhau. Tuy nhiên, nó sẽ dễ dàng xác định 1) tập tin nào sẽ được sao chép; 2) cái nào cần hợp nhất thủ công.


Nó không làm chính xác những gì OP yêu cầu, nhưng có vẻ như nó hoàn thành mục tiêu cuối cùng của OP. +1
Ryan C. Thompson

+1 Đáng buồn thay, máy chủ tôi đang chạy này không được cài đặt unison, tôi cũng không có quyền để cài đặt nó. Nhưng đây có thể là một câu trả lời tốt cho người khác.
David Oneill

1
Bạn có thể tải xuống unison thực thi từ sea.upenn.edu/~bcpierce/unison//doad/ . Cài đặt nó ở đâu đó trong thư mục nhà của bạn, nó chỉ là một tệp.
JooMing

2

Các kịch bản sau đây nên làm những điều hợp lý. Nó di chuyển các tệp từ nguồn đến đích, không bao giờ ghi đè tệp và tạo thư mục khi cần thiết. Các tệp nguồn có một tệp khác nhau tương ứng ở đích được để riêng, cũng như các tệp không phải là tệp hoặc thư mục thông thường (ví dụ: liên kết tượng trưng). Các tệp còn lại trong nguồn là những tệp có xung đột. Coi chừng, tôi chưa thử nó chút nào.

cd src
find . -exec sh -c '
    set -- "/path/to/dest/$0"
    if [ -d "$0" ]; then #  the source is a directory 
      if ! [ -e "$1" ]; then
        mv -- "$0" "$1"  # move whole directory in one go
      fi
    elif ! [ -e "$0" ]; then  # the source doesn't exist after all
      :  # might happen if a whole directory was moved
    elif ! [ -e "$1" ]; then  # the destination doesn't exist
      mv -- "$0" "$1"
    elif [ -f "$1" ] && cmp -s -- "$0" "$1"; then  # identical files
      rm -- "$0"
    fi
  ' {} \;

Một cách tiếp cận khác là thực hiện một liên kết gắn kết một thư mục khác, ví dụ với funionfs hoặc unionfs-fuse .

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.