rsync: Đồng bộ hóa thư mục, nhưng giữ các tệp bổ sung trong mục tiêu


10

Tôi đang bắt đầu rsyncvà cố gắng sử dụng nó để giữ cho hai thư mục trên hệ thống cục bộ được đồng bộ hóa. Tôi có một thư mục nguồn, có nội dung thay đổi theo thời gian (một số tệp được thêm vào, một số thay đổi và một số bị xóa) và một thư mục đích mà tôi muốn gần như là một tấm gương của nguồn. Vì vậy, những gì tôi đã thử là sử dụng rsync như thế này:

rsync -a --delete "${source_dir}" "${target_dir}";

Điều này không giữ cho nội dung của mục tiêu giống hệt như nội dung của nguồn. Tuy nhiên, tôi muốn có thể thêm một số tệp để nhắm mục tiêu và không vào nguồn, nhưng tôi không muốn chúng bị xóa mỗi khi tôi thực hiện rsync. Mặt khác, các tệp đã được đồng bộ hóa và sau đó bị xóa trong nguồn vẫn sẽ bị xóa.

Có cách nào để làm điều này mà không phải thay đổi lệnh cho mọi tệp mà tôi muốn loại trừ không?

Cập nhật : Tôi nên đề cập rằng tôi không giới hạn rsync. Nếu một chương trình khác hoàn thành công việc, điều đó cũng tốt. Tôi chỉ cố gắng giải quyết điều này bằng cách sử dụng rsync.


Xin chào @AszunesHeart, chỉ tò mò, nhưng bạn đã kiểm tra (các) câu trả lời chưa?
Jacob Vlijm

Bạn đã thử dùng tùy chọn --delete chưa? Cái đó giống như tùy chọn / MIR trong Robocopy.
SDsolar

Câu trả lời:


9

rsynccó một tùy chọn được gọi là --exclude-fromtùy chọn cho phép bạn tạo một tệp chứa danh sách bất kỳ tệp nào bạn muốn loại trừ. Bạn có thể cập nhật tệp này bất cứ khi nào bạn muốn thêm loại trừ mới hoặc xóa tệp cũ.

Nếu bạn tạo tệp loại trừ tại /home/user/rsync_excludelệnh mới sẽ là:

rsync -a --delete --exclude-from="/home/user/rsync_exclude" "${source_dir}" "${target_dir}"

Khi tạo tệp danh sách loại trừ, bạn nên đặt từng quy tắc loại trừ trên một dòng riêng biệt. Các loại trừ có liên quan đến thư mục nguồn của bạn. Nếu /home/user/rsync_excludetệp của bạn chứa các tùy chọn sau:

secret_file
first_dir/subdir/*
second_dir/common_name.*
  • Bất kỳ tập tin hoặc thư mục được gọi secret_filetrong thư mục nguồn của bạn sẽ được loại trừ.
  • Mọi tệp trong ${source_dir}/first_dir/subdirsẽ bị loại trừ, nhưng phiên bản trống subdirsẽ được đồng bộ hóa.
  • Bất kỳ tệp nào ${source_dir}/second_dircó tiền tố common_name.sẽ bị bỏ qua. Vì vậy common_name.txt, common_name.jpgvv

Tôi không chắc chắn nếu điều này làm những gì tôi muốn. Ngoài ra tôi thấy không thực tế khi liệt kê mọi tệp hoặc thư mục được thêm vào mục tiêu. Tôi muốn có một cách tự động để làm điều đó. Giả sử tôi có nhiều tập lệnh khác nhau trong mục tiêu tạo ra nhiều tệp nhật ký (cũng trong mục tiêu) và tôi không muốn liệt kê mọi vị trí của các tệp đó trong tệp rsync_exclude. Có cách nào để làm cho rsync "nhớ" những tệp nào được đồng bộ hóa và chỉ để những tệp đó bị ảnh hưởng bởi --delete không?
jkrzefski

Xin lỗi, tôi đã đọc sai câu hỏi của bạn, mặc dù bạn muốn thêm vào nguồn và những người không cập nhật mục tiêu. Tôi nghĩ rằng có một cách để làm những gì bạn muốn, nhưng tôi sẽ phải suy nghĩ một chút. Tôi sẽ bình luận một khi tôi có thời gian để chỉnh sửa.
Arronical

@jkrzefski Nếu bạn đang tạo tệp từ một tập lệnh khác trong mục tiêu và muốn loại trừ chúng khỏi nguồn, thì tại sao không thay đổi đích của các tệp nhật ký đó sang thư mục khác? Có lẽ, nếu bạn không đồng bộ hóa chúng, là bởi vì chúng ít quan trọng hơn.

6

Vì bạn đã đề cập: Tôi không giới hạn ở rsync:

Script để duy trì máy nhân bản, cho phép thêm tệp bổ sung vào mục tiêu

Bên dưới một kịch bản thực hiện chính xác những gì bạn mô tả.

Kịch bản có thể được chạy trong chế độ dài dòng (sẽ được đặt trong tập lệnh), sẽ tạo ra tiến trình sao lưu (phản chiếu). Không cần phải nói điều này cũng có thể được sử dụng để đăng nhập các bản sao lưu:

Tùy chọn dài dòng

nhập mô tả hình ảnh ở đây


Khái niệm

1. Trong lần sao lưu đầu tiên, tập lệnh:

  • tạo một tệp (trong thư mục đích), trong đó tất cả các tệp và thư mục được liệt kê; .recentfiles
  • tạo một bản sao chính xác (bản sao) của tất cả các tệp và thư mục trong thư mục đích

2. Tiếp theo và sao lưu

  • Kịch bản so sánh cấu trúc thư mục và (các) ngày sửa đổi của các tệp. Các tập tin và thư mục mới trong nguồn được sao chép vào máy nhân bản. Đồng thời một tệp thứ hai (tạm thời) được tạo, liệt kê các tệp và thư mục hiện tại trong thư mục nguồn; .currentfiles.
  • Sau đó, .recentfiles(liệt kê tình huống trên bản sao lưu trước) được so sánh với .currentfiles. Chỉ các tệp .recentfileskhông có trong .currentfilesđó rõ ràng bị xóa khỏi nguồn và sẽ bị xóa khỏi mục tiêu.
  • Các tập tin bạn đã thêm thủ công vào thư mục đích không nằm trong tập lệnh "được nhìn thấy" và được để lại một mình.
  • Cuối cùng, tạm thời .currentfilesđược đổi tên thành .recentfilesđể phục vụ chu kỳ sao lưu tiếp theo, v.v.

Kịch bản

#!/usr/bin/env python3
import os
import sys
import shutil

dr1 = sys.argv[1]; dr2 = sys.argv[2]

# --- choose verbose (or not)
verbose = True
# ---

recentfiles = os.path.join(dr2, ".recentfiles")
currentfiles = os.path.join(dr2, ".currentfiles")

if verbose:
    print("Counting items in source...")
    file_count = sum([len(files)+len(d) for r, d, files in os.walk(dr1)])
    print(file_count, "items in source")
    print("Reading directory & file structure...")
    done = 0; chunk = int(file_count/5); full = chunk*5

def show_percentage(done):
    if done % chunk == 0:
        print(str(int(done/full*100))+"%...", end = " ")

for root, dirs, files in os.walk(dr1):
    for dr in dirs:
        if verbose:
            if done == 0:
                print("Updating mirror...")
            done = done + 1
            show_percentage(done) 
        target = os.path.join(root, dr).replace(dr1, dr2)
        source = os.path.join(root, dr)
        open(currentfiles, "a+").write(target+"\n")
        if not os.path.exists(target):
            shutil.copytree(source, target)
    for f in files:
        if verbose:
            done = done + 1
            show_percentage(done)
        target = os.path.join(root, f).replace(dr1, dr2)
        source = os.path.join(root, f)
        open(currentfiles, "a+").write(target+"\n") 
        sourcedit = os.path.getmtime(source)
        try:
            if os.path.getmtime(source) > os.path.getmtime(target):
                shutil.copy(source, target)   
        except FileNotFoundError:
            shutil.copy(source, target)

if verbose:
    print("\nChecking for deleted files in source...")

if os.path.exists(recentfiles):
    recent = [f.strip() for f in open(recentfiles).readlines()]
    current = [f.strip() for f in open(currentfiles).readlines()]
    remove = set([f for f in recent if not f in current])
    for f in remove:
        try:
            os.remove(f)
        except IsADirectoryError:
            shutil.rmtree(f)
        except FileNotFoundError:     
            pass
        if verbose:
            print("Removed:", f.split("/")[-1])

if verbose:
    print("Done.")

shutil.move(currentfiles, recentfiles)

Cách sử dụng

  1. Sao chép tập lệnh vào một tập tin trống, lưu nó dưới dạng backup_special.py
  2. Thay đổi - nếu bạn muốn- tùy chọn dài dòng trong phần đầu của tập lệnh:

    # --- choose verbose (or not)
    verbose = True
    # ---
    
  3. Chạy nó với nguồn và đích làm đối số:

     python3 /path/to/backup_special.py <source_directory> <target_directory>
    

Tốc độ

Tôi đã thử nghiệm tập lệnh trên thư mục 10 GB với khoảng 40.000 tệp và thư mục trên ổ đĩa mạng (NAS), nó đã tạo bản sao lưu trong cùng thời gian với rsync.

Cập nhật toàn bộ thư mục chỉ mất một vài giây hơn rsync, trên 40.000 tác phẩm, đó là imo chấp nhận được và không ngạc nhiên, vì kịch bản cần so sánh nội dung để sao lưu cuối cùng thực hiện.


Xin chào @ Aszune'sHeart đã thêm một tùy chọn theo kịch bản. Hãy đề cập nếu tất cả là rõ ràng.
Jacob Vlijm
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.