Я начинаю с rsync
и попробованный для использования его для хранения двух папок в локальной системе синхронизировавшими. У меня есть исходная папка, содержание которой изменяется со временем (некоторые файлы добавляются, некоторые изменения и некоторые удаленные), и целевая папка, что я хочу почти быть зеркалом источника. Таким образом, то, что я попробовал, использовало rsync как это:
rsync -a --delete "${source_dir}" "${target_dir}";
Это действительно сохраняет содержание цели тем же самым как содержание источника. Однако я хотел бы смочь добавить некоторые файлы для предназначения а не к источнику, но я не хочу, чтобы они были удалены каждый раз, я делаю rsync. С другой стороны, файлы, которые раньше синхронизировались и затем были удалены в источнике, должны все еще быть удалены.
Существует ли способ сделать это, не имея необходимость изменять команду для каждого файла, который я хочу исключенный?
Обновление: Я должен упомянуть, что не ограничен rsync. Если другая программа сделала задание, это прекрасно также. Я просто попытался решить это использование rsync.
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
и т.д.Так как Вы упомянули: Я не ограничен rsync:
Ниже сценария, который делает точно, что Вы описываете.
Скрипт может быть запущен в подробном режиме (чтобы быть установленным в сценарии), который произведет прогресс резервного (зеркальное отражение). Никакая потребность сказать это не может также использоваться для входа резервных копий:
Подробная опция
.recentfiles
.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 файлов, который является imo приемлемый и не удивительно, так как сценарий должен сравнить содержание с последним сделанным резервным копированием.