Оскільки ви згадали: я не обмежуюся 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)
Як користуватись
- Скопіюйте скрипт у порожній файл, збережіть його як
backup_special.py
Змініть - якщо ви хочете - параметр багатослівного в голові сценарію:
# --- choose verbose (or not)
verbose = True
# ---
Запустити його з джерелом та ціллю в якості аргументів:
python3 /path/to/backup_special.py <source_directory> <target_directory>
Швидкість
Я протестував сценарій у 10 ГБ директорії з приблизно 40.000 файлів і брусів на моєму мережевому диску (NAS), це створило резервну копію майже в той же час, що і rsync.
Оновлення всього каталогу зайняло лише кілька секунд більше, ніж rsync, на 40 000 файлів, що є прийнятним і не дивно, оскільки сценарій повинен порівнювати вміст з останньою створеною резервною копією.