rsync: Klasörleri senkronize et, ancak fazladan dosyaları hedefte tut


10

Birlikte başlıyorum rsyncve senkronize yerel sistemde iki klasör tutmak için kullanmaya çalıştı. İçeriği zamanla değişen bir kaynak klasörüm var (bazı dosyalar ekleniyor, bazı değişiklikler ve bazıları silindi) ve neredeyse kaynağın aynası olmasını istediğim bir hedef klasör var. Ne denedim rsync böyle kullanmak oldu:

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

Bu, hedefin içeriğini kaynağın içeriğiyle aynı tutar. Ancak, kaynak değil, hedefe bazı dosyalar eklemek istiyorum, ancak rsync her yaptığımda silinmesini istemiyorum. Öte yandan, eskiden senkronize edildikten sonra kaynakta silinen dosyalar yine de silinmelidir.

Dışlamak istediğim her dosya için komutu değiştirmek zorunda kalmadan bunu yapmanın bir yolu var mı?

Güncelleme : Rsync ile sınırlı olmadığımı belirtmeliyim. Başka bir program işi yaparsa, bu da iyi. Bunu rsync kullanarak çözmeye çalıştım.


Merhaba @AszunesHeart, sadece merak ettim, ama cevapları test ettin mi?
Jacob Vlijm

--Delete seçeneğini kullanmayı denediniz mi? Bu Robocopy'deki / MIR seçeneği gibidir.
SDsolar

Yanıtlar:


8

rsync--exclude-fromhariç tutmak istediğiniz dosyaların listesini içeren bir dosya oluşturmanıza olanak tanıyan seçenek adlı bir seçeneğe sahiptir. Yeni bir hariç tutma eklemek veya eski bir dosyayı kaldırmak istediğinizde bu dosyayı güncelleyebilirsiniz.

Dışlama dosyasını /home/user/rsync_excludeyeni komutta oluşturursanız:

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

Hariç tutma listesi dosyasını oluştururken, her hariç tutma kuralını ayrı bir satıra koymalısınız. Hariç tutmalar kaynak dizininize göredir. Eğer /home/user/rsync_excludedosya aşağıdaki seçenekleri içeriyordu:

secret_file
first_dir/subdir/*
second_dir/common_name.*
  • secret_fileKaynak dizininizde çağrılan herhangi bir dosya veya dizin hariç tutulur.
  • İçindeki tüm dosyalar ${source_dir}/first_dir/subdirhariç tutulacak, ancak boş bir sürümü subdirsenkronize edilecek.
  • ${source_dir}/second_dirÖneki bulunan tüm dosyalar common_name.yok sayılır. Yani common_name.txt, common_name.jpgvs.

1
Bunun istediğimi yapıp yapmadığından emin değilim. Ayrıca hedefe eklenen her dosya veya klasörü listelemek pratik değildir. Bunu yapmanın otomatik bir yoluna sahip olmayı tercih ederim. Diyelim ki birden çok günlük dosyası (hedefte de) üreten çeşitli komut dosyalarına sahibim ve bu dosyaların rsync_exclude dosyasındaki her konumunu listelemek istemiyorum. Rsync'in hangi dosyaları senkronize edildiği "hatırlaması" ve sadece --delete'den etkilenmesine izin vermenin bir yolu var mı?
jkrzefski

Üzgünüz, sorunuzu yanlış okudum, ancak kaynağa eklemek istediniz ve bunların hedeflenecek şekilde güncellenmemesini sağladım. Sanırım istediğini yapmanın bir yolu var, ama biraz düşünmek zorunda kalacağım. Düzenlemek için zamanım olduğunda yorum yapacağım.
Arronik

@jkrzefski Hedefteki başka bir komut dosyasından dosya oluşturuyorsanız ve bunları kaynaktan hariç tutmak istiyorsanız, neden bu günlük dosyalarının hedefini başka bir klasöre değiştirmeyesiniz? Muhtemelen, onları senkronize etmiyorsanız, daha az önemli oldukları içindir.

6

Bahsettiğinizden beri: rsync ile sınırlı değilim:

Yansımayı korumak için komut dosyası, hedefe fazladan dosya eklenmesine izin verme

Tam olarak tarif ettiğiniz şeyi yapan bir komut dosyasının altında.

Komut dosyası , yedeklemenin ilerlemesini (yansıtma) çıkaracak ayrıntılı modda (komut dosyasında ayarlanacak) çalıştırılabilir. Bunun yedeklemeleri günlüğe kaydetmek için de kullanılabileceğini söylemeye gerek yok:

Ayrıntılı seçenek

resim açıklamasını buraya girin


Kavram

1. İlk yedeklemede komut dosyası:

  • tüm dosyaların ve dizinlerin listelendiği bir dosya (hedef dizinde) oluşturur; .recentfiles
  • hedef dizindeki tüm dosyaların ve dizinlerin tam bir kopyasını (ayna) oluşturur

2. sonraki ve böylece yedekleme

  • Komut dosyası, dosyaların dizin yapısını ve değişiklik tarihlerini karşılaştırır. Kaynaktaki yeni dosyalar ve dizinler aynaya kopyalanır. Aynı zamanda, kaynak dizindeki geçerli dosyaları ve dizinleri listeleyen ikinci (geçici) bir dosya oluşturulur; .currentfiles.
  • Daha sonra, .recentfiles(önceki yedeklemedeki durumu listelemek) ile karşılaştırılır .currentfiles. Yalnızca içinde.recentfiles bulunmayan dosyalar .currentfileskaynaktan açıkça kaldırılır ve hedeften kaldırılır.
  • Hedef klasöre el ile eklediğiniz dosyalar komut dosyası tarafından "görülmez" ve tek başına bırakılır.
  • Son olarak, geçici .currentfilesolarak bir .recentfilessonraki yedekleme döngüsüne hizmet edecek şekilde yeniden adlandırılır .

Senaryo

#!/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)

Nasıl kullanılır

  1. Komut dosyasını boş bir dosyaya kopyalayın, backup_special.py
  2. Komut dosyasının başındaki ayrıntılı seçeneği (isterseniz) değiştirin:

    # --- choose verbose (or not)
    verbose = True
    # ---
    
  3. Kaynağı ve hedefi bağımsız değişken olarak çalıştırın:

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

hız

Komut dosyasını 10 GB'lık bir dizinde ağ sürücümde (NAS) 40.000 dosya ve dizinle test ettim, yedeklemeyi hemen hemen rsync ile aynı zamanda yaptım.

Tüm dizini güncellemek , 40.000 dosyada rsync'den sadece birkaç saniye daha sürdü, bu imo kabul edilebilir ve sürpriz değil, çünkü komut dosyasının içeriği son yapılan yedekle karşılaştırması gerekiyor.


Hi @ Aszune'sHeart bir komut dosyası seçeneği ekledi. Lütfen her şeyin açık olup olmadığını belirtin.
Jacob Vlijm
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.