Desde que você mencionou: não estou limitado a rsync:
Script para manter o espelho, permitindo adicionar arquivos extras para segmentar
Abaixo de um script que faz exatamente o que você descreve.
O script pode ser executado no modo detalhado (a ser definido no script), que exibirá o progresso do backup (espelhamento). Não é necessário dizer que isso também pode ser usado para registrar os backups:
Opção detalhada
O conceito
1. No primeiro backup, o script:
- cria um arquivo (no diretório de destino), onde todos os arquivos e diretórios são listados; %código%
- cria uma cópia exata (espelho) de todos os arquivos e diretórios no diretório de destino
2. No backup seguinte e assim por diante
- O script compara a estrutura de diretórios e a (s) data (s) de modificação dos arquivos. Novos arquivos e dirs na origem são copiados para o espelho. Ao mesmo tempo, um segundo arquivo (temporário) é criado, listando os arquivos e diretórios atuais no diretório de origem;
.recentfiles
.
- Posteriormente,
.currentfiles
(listando a situação no backup anterior) é comparado a .recentfiles
. Somente arquivos de .currentfiles
que não estão em .recentfiles
são obviamente removidos da origem e serão removidos do destino.
- Os arquivos que você adicionou manualmente à pasta de destino não aparecem de forma alguma "vistos" pelo script e são deixados em paz.
- Finalmente, o
.currentfiles
temporário é renomeado para .currentfiles
para atender ao próximo ciclo de backup e assim por diante.
O script
#!/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)
Como usar
- Copie o script em um arquivo vazio, salve-o como
.recentfiles
-
Altere-se desejar - a opção detalhada na cabeça do script:
# --- choose verbose (or not)
verbose = True
# ---
-
Execute-o com origem e destino como argumentos:
python3 /path/to/backup_special.py <source_directory> <target_directory>
Velocidade
Eu testei o script em um diretório de 10 GB com cerca de 40.000 arquivos e dirs na minha unidade de rede (NAS), ele fez o backup praticamente ao mesmo tempo que o rsync.
Atualizando o diretório inteiro levou apenas alguns segundos a mais do que o rsync, em 40.000 arquivos, o que é imo aceitável e não é surpresa, já que o script precisa comparar o conteúdo ao último backup feito. / p>