rsync --delete con carpeta de destino superconjunto

rsync --delete con carpeta de destino superconjunto

Tengo un rsyncproceso que sincroniza contenido de un repositorio de origen (que está controlado por versión) en un montaje NFS compartido.

El escenario (por más terrible que sea) es que la carpeta de destino contiene más contenido que la carpeta de origen porque otro contenido se sincroniza con la carpeta de destino desde diferentes fuentes. Así, por ejemplo, las estructuras de carpetas pueden verse así:

fuente

a/a1.txt
a/a2.txt
b/b1.txt

destino

a/a1.txt
a/a2.txt
a/a3.txt
b/b1.txt
c/c1.txt

(en este ejemplo, a/a3.txty c/c1.txtestán sincronizados con el destino desde otro lugar. En la práctica, esto involucra muchas otras fuentes y no se puede influir en el contenido/procesos de estas).

Ahora digamos que la carpeta de origen elimina el a/a2.txtarchivo. Con la configuración existente, este archivo no se eliminará en el destino; pero usarlo --deleteresultaría en la eliminación de otros archivos, y es un requisito no hacerlo.

¿Cómo podría --deleteusarse en este rsync pero cumplir con el requisito? Debido a que la versión del directorio fuente está controlada, es bastante sencillo obtener un antes y un después de este directorio, por lo que se podría calcular una copia de seguridad diferencial utilizando el directorio fuente original como referencia, pero ¿es esta la mejor manera?

Respuesta1

No puedes usarlo rsync --deleteasí. No tiene estado y no guarda ningún registro de qué archivos se han eliminado entre ejecuciones. La --deletebandera simplemente indica rsyncque se eliminen todos los archivos del destino que no existan en el origen.

Para implementar esta eliminación restringida, creo que es necesario mantener su propio estado. Ni rsyncni unisonpuedo hacer esto por ti.

La siguiente no es una solución totalmente segura contra errores; es un punto de partida. (Sin embargo, maneja archivos con nombres extraños, incluidos aquellos que contienen una nueva línea incrustada).

Supongamos dos directorios srcy dst. (Para los propósitos del ejemplo, realmente no importa si dstes local o remoto).

# Find the current list of files (do this just once, to prep the cache)
( cd src && find . -type f -print0 ) | LC_ALL=C sort -z > .state.src

Cada vez que realicemos una copia de seguridad, ejecute el siguiente código

# Run the rsync to transfer files. "dst/" could be local
rsync -av src/ remote:dst/

# Determine the set of files to delete in "dst/"
( cd src && find . -type f -print0 ) | LC_ALL=C sort -z | tee .state.src.new |
    LC_ALL=C comm -z - -13 .state.src |
    ssh remote 'while IFS= read -d "" -r f; do rm -f "dst/$f"; done'

# That seemed to work, so update the state cache
[[ 0 -eq $? ]] && mv -f .state.src.new .state.src

Si su versión comm(como la mía) es anterior a GNU coreutils 8.25 y no tiene la -zbandera, puede usar esta solución alternativa:

# Find the current list of files (do this just once, to prep the cache)
( cd src && find . -type f -print0 ) | tr '\0\n' '\n\0' | LC_ALL=C sort > .state.src

Cada vez que realicemos una copia de seguridad, ejecute el siguiente código

# Run the rsync to transfer files. "dst/" could be local
rsync -av src/ remote:dst/

# Determine the set of files to delete in "dst/"
( cd src && find . -type f  -print0 ) | tr '\0\n' '\n\0' | LC_ALL=C sort | tee .state.src.new |
    LC_ALL=C comm -13 - .state.src |
    tr '\0\n' '\n\0' |
    ssh remote 'while IFS= read -d "" -r f; do rm -f "dst/$f"; done'

# That seemed to work, so update the state cache
[[ 0 -eq $? ]] && mv -f .state.src.new .state.src

información relacionada