Como mencionó: no estoy limitado a rsync:
Script para mantener el espejo, lo que permite agregar archivos adicionales al destino
Debajo de un script que hace exactamente lo que usted describe.
La secuencia de comandos se puede ejecutar en modo detallado (que se establecerá en la secuencia de comandos), lo que generará el progreso de la copia de seguridad (reflejo). No es necesario decir que esto también se puede usar para registrar las copias de seguridad:
Opción detallada
El concepto
1. En la primera copia de seguridad, el script:
- crea un archivo (en el directorio de destino), donde se enumeran todos los archivos y directorios;
.recentfiles
- crea una copia exacta (espejo) de todos los archivos y directorios en el directorio de destino
2. En el siguiente y así sucesivamente copia de seguridad
- El script compara la estructura del directorio y las fechas de modificación de los archivos. Los nuevos archivos y directorios en la fuente se copian en el espejo. Al mismo tiempo, se crea un segundo archivo (temporal), que enumera los archivos y directorios actuales en el directorio de origen;
.currentfiles
.
- Posteriormente,
.recentfiles
se compara (enumerando la situación en la copia de seguridad anterior) .currentfiles
. Obviamente, solo los archivos de los .recentfiles
que no .currentfiles
están se eliminan del origen y se eliminarán del destino.
- Los archivos que agregó manualmente a la carpeta de destino no son "vistos" de ninguna manera por el script, y se dejan solos.
- Finalmente, el nombre temporal
.currentfiles
se renombra para .recentfiles
servir el próximo ciclo de copia de seguridad y así sucesivamente.
La secuencia de comandos
#!/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)
Cómo utilizar
- Copie el script en un archivo vacío, guárdelo como
backup_special.py
Cambie, si lo desea, la opción detallada en el encabezado del script:
# --- choose verbose (or not)
verbose = True
# ---
Ejecútelo con fuente y destino como argumentos:
python3 /path/to/backup_special.py <source_directory> <target_directory>
Velocidad
Probé el script en un directorio de 10 GB con unos 40,000 archivos y directorios en mi unidad de red (NAS), hizo la copia de seguridad casi al mismo tiempo que rsync.
La actualización de todo el directorio tomó solo unos segundos más que rsync, en 40,000 archivos, lo cual es bastante aceptable y no sorprende, ya que el script necesita comparar el contenido con la última copia de seguridad realizada.