rsync: синхронізуйте папки, але зберігайте зайві файли в цілі


10

Я починаю rsyncі намагаюся використовувати його, щоб зберегти дві папки в локальній системі. У мене є вихідна папка, вміст якої змінюється з часом (деякі файли додаються, деякі змінюються, а деякі видаляються) та цільову папку, яку я хочу майже бути дзеркалом джерела. Тому я спробував використовувати rsync так:

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

Це зберігає вміст націленого так само, як і вміст джерела. Однак я хотів би мати можливість додавати деякі файли до націлювання, а не до джерела, але я не хочу, щоб вони видалялися кожного разу, коли я роблю rsync. З іншого боку, файли, які синхронізувались та видалялись у джерелі, все одно слід видаляти.

Чи є спосіб це зробити, не змінюючи команди для кожного виключеного файлу?

Оновлення : Я мушу зазначити, що я не обмежений rsync. Якщо інша програма виконає роботу, це теж добре. Я просто намагався вирішити це за допомогою rsync.


Привіт @AszunesHeart, просто цікаво, але ви перевіряли відповіді?
Яків Влійм

Ви спробували зняти варіант --delete? Ця схожа на параметр / MIR в роботокопії.
SDsolar

Відповіді:


8

rsyncє опція під назвою --exclude-fromопція, яка дозволяє створити файл, що містить перелік усіх файлів, які ви хочете виключити. Ви можете оновлювати цей файл, коли потрібно додати нове виключення або видалити старий.

Якщо створити файл виключення в /home/user/rsync_excludeновій команді, було б:

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

Створюючи файл списку виключень, слід поставити кожне правило виключення в окремий рядок. Виключення відносяться до вашого вихідного каталогу. Якщо ваш /home/user/rsync_excludeфайл містив такі параметри:

secret_file
first_dir/subdir/*
second_dir/common_name.*
  • Будь-який файл або каталог, названий secret_fileу вашому вихідному каталозі, буде виключений
  • Будь-які файли в ${source_dir}/first_dir/subdirбуде виключено, але порожня версія файлу subdirбуде синхронізована.
  • Будь-які файли ${source_dir}/second_dirз префіксом common_name.ігноруються. Так common_name.txtі common_name.jpgт.д.

1
Я не впевнений, чи робить це те, що я хотів. Крім того, я вважаю недоцільним перераховувати кожен файл або папку, яка додається до цілі. Я б хотів мати автоматичний спосіб зробити це. Скажімо, у мене в цілі є різні сценарії, які створюють декілька файлів журналу (також у цільовому), і я не хочу перераховувати кожне розташування цих файлів у rsync_exclude-файлі. Чи є спосіб змусити rsync "запам'ятати", які файли синхронізовано, і лише нехай на них впливає --delete?
jkrzefski

Вибачте, я неправильно прочитав ваше запитання, хоча ви хотіли додати його до джерела, а ті, які не оновлюються для націлювання. Я думаю, що є спосіб зробити те, що ти хочеш, але мені доведеться трохи обдумати це. Я коментую, як тільки встигну редагувати.
Арронічний

@jkrzefski Якщо ви створюєте файли з іншого скрипту в цільовому об'єкті і хочете виключити їх із джерела, то чому б не змінити призначення цих файлів журналу на іншу папку? Імовірно, якщо ви їх не синхронізуєте, це тому, що вони менш важливі.

6

Оскільки ви згадали: я не обмежуюся rsync:

Сценарій для підтримки дзеркала, що дозволяє додавати додаткові файли для націлювання

Нижче сценарій, який робить саме те, що ви описали.

Сценарій можна запустити у багатослівному режимі (встановити в сценарії), що виведе хід резервного копіювання (дзеркальне відображення). Не потрібно говорити, що це також можна використовувати для реєстрації резервних копій:

Докладний варіант

введіть тут опис зображення


Концепція

1. Під час першого резервного копіювання сценарій:

  • створює файл (у цільовому каталозі), де перераховані всі файли та каталоги; .recentfiles
  • створює точну копію (дзеркало) всіх файлів і каталогів у цільовому каталозі

2. На наступному тощо

  • Сценарій порівнює структуру каталогів та дати модифікації файлів. Нові файли та файли у джерелі копіюються у дзеркало. Одночасно створюється другий (тимчасовий) файл, в якому перераховані поточні файли та dirs у вихідному каталозі; .currentfiles.
  • Згодом .recentfiles(перелік ситуації за попередньою резервною копією) порівнюється з .currentfiles. Тільки файли, з .recentfilesяких немає .currentfiles, очевидно видаляються з джерела та будуть видалені з цілі.
  • Файли, які ви вручну додали до цільової папки, ні в якому разі не "бачили" сценарій, і залишаються в спокої.
  • Нарешті, тимчасова .currentfilesперейменована на .recentfilesобслуговування наступного циклу резервного копіювання тощо.

Сценарій

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

Як користуватись

  1. Скопіюйте скрипт у порожній файл, збережіть його як backup_special.py
  2. Змініть - якщо ви хочете - параметр багатослівного в голові сценарію:

    # --- choose verbose (or not)
    verbose = True
    # ---
    
  3. Запустити його з джерелом та ціллю в якості аргументів:

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

Швидкість

Я протестував сценарій у 10 ГБ директорії з приблизно 40.000 файлів і брусів на моєму мережевому диску (NAS), це створило резервну копію майже в той же час, що і rsync.

Оновлення всього каталогу зайняло лише кілька секунд більше, ніж rsync, на 40 000 файлів, що є прийнятним і не дивно, оскільки сценарій повинен порівнювати вміст з останньою створеною резервною копією.


Привіт @ Aszune'sHeart додав сценарій. Будь ласка, зазначте, якщо все зрозуміло.
Яків Влійм
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.