Поскольку вы упомянули: я не ограничен rsync:
Скрипт для поддержки зеркала, позволяющий добавлять дополнительные файлы к цели
Ниже сценарий, который делает именно то, что вы описываете.
Сценарий может быть запущен в подробном режиме (устанавливается в сценарии), который будет отображать ход выполнения резервного копирования (зеркальное отображение). Нет необходимости говорить, что это также может быть использовано для регистрации резервных копий:
Подробный вариант
Концепт
1. При первом резервном копировании скрипт:
- создает файл (в целевом каталоге), в котором перечислены все файлы и каталоги;
.recentfiles
- создает точную копию (зеркало) всех файлов и каталогов в целевом каталоге
2. На следующем и т. Д. Бэкапе
- Скрипт сравнивает структуру каталогов и дату (ы) изменения файлов. Новые файлы и каталоги в источнике копируются в зеркало. В то же время создается второй (временный) файл, в котором перечислены текущие файлы и каталоги в исходном каталоге;
.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 файлов, что неприемлемо, и это неудивительно, поскольку сценарию необходимо сравнить содержимое с последней сделанной резервной копией.