rsync: sincroniza carpetas, pero mantiene archivos adicionales en el destino

rsync: sincroniza carpetas, pero mantiene archivos adicionales en el destino

Estoy comenzando rsynce intenté usarlo para mantener sincronizadas dos carpetas en el sistema local. Tengo una carpeta de origen, cuyo contenido cambia con el tiempo (algunos archivos se agregan, algunos cambian y otros se eliminan) y una carpeta de destino que quiero que sea casi un espejo de la fuente. Entonces lo que intenté fue usar rsync de esta manera:

rsync -a --delete "${source_dir}" "${target_dir}";

Esto mantiene el contenido del destino exactamente igual que el contenido del origen. Sin embargo, me gustaría poder agregar algunos archivos al destino y no al origen, pero no quiero que se eliminen cada vez que hago rsync. Por otro lado, los archivos que solían sincronizarse y luego se eliminaron en la fuente aún deberían eliminarse.

¿Hay alguna manera de hacer esto sin tener que modificar el comando para cada archivo que quiero excluir?

Actualizar: Debo mencionar que no estoy limitado a rsync. Si otro programa hace el trabajo, también está bien. Intenté resolver esto usando rsync.

Respuesta1

rsynctiene una opción llamada --exclude-fromopción que le permite crear un archivo que contiene una lista de los archivos que desea excluir. Puede actualizar este archivo siempre que desee agregar una nueva exclusión o eliminar una anterior.

Si crea el archivo de exclusión con /home/user/rsync_excludeel nuevo comando sería:

rsync -a --delete --exclude-from="/home/user/rsync_exclude" "${source_dir}" "${target_dir}"

Al crear el archivo de lista de exclusión, debe colocar cada regla de exclusión en una línea separada. Las exclusiones son relativas a su directorio de origen. Si su /home/user/rsync_excludearchivo contenía las siguientes opciones:

secret_file
first_dir/subdir/*
second_dir/common_name.*
  • secret_fileSe excluirá cualquier archivo o directorio llamado en su directorio de origen.
  • ${source_dir}/first_dir/subdirSe excluirán todos los archivos , pero subdirse sincronizará una versión vacía.
  • Se ignorarán todos los archivos ${source_dir}/second_dircon el prefijo de . common_name.Así common_name.txt, common_name.jpgetc.

Respuesta2

Ya que mencionaste:No estoy limitado a rsync:

Script para mantener el espejo, permitiendo agregar archivos adicionales al objetivo.

Debajo de un script que hace exactamente lo que usted describe.

El script se puede ejecutar enverbosomodo (que se configurará en el script), que generará el progreso de la copia de seguridad (duplicación). No hace falta decir que esto también se puede utilizar para registrar las copias de seguridad:

Opción detallada

ingrese la descripción de la imagen aquí


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 la siguiente copia de seguridad y así sucesivamente.

  • El script compara la estructura del directorio y las fechas de modificación de los archivos. Los nuevos archivos y directorios del origen 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(enumerando la situación en la copia de seguridad anterior) se compara con .currentfiles.SoloLos archivos .recentfilesque no están .currentfilesobviamente se eliminan del origen y se eliminarán del destino.
  • Los archivos que agregó manualmente a la carpeta de destino no son "vedos" de ninguna manera por el script y se dejan en paz.
  • Finalmente, .currentfilesse cambia el nombre del temporal para .recentfilesque sirva para el siguiente ciclo de respaldo 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

  1. Copie el script en un archivo vacío, guárdelo comobackup_special.py
  2. Cambia -si quieres- la opción detallada en el encabezado del script:

    # --- choose verbose (or not)
    verbose = True
    # ---
    
  3. Ejecútelo con origen 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), realizó la copia de seguridad prácticamente al mismo tiempo que rsync.

Actualizandotodo el directorio tomó solo unos segundos más que rsync, en 40,000 archivos, lo cual es, en mi opinión, aceptable y no sorprende, ya que el script necesita comparar el contenido con la última copia de seguridad realizada.

información relacionada