rsync --delete com pasta de destino do superconjunto

rsync --delete com pasta de destino do superconjunto

Eu tenho um rsyncprocesso que está sincronizando conteúdo de um repositório de origem (que é controlado por versão) em uma montagem NFS compartilhada.

O cenário (por mais terrível que seja) é que a pasta de destino contém mais conteúdo do que a pasta de origem porque outro conteúdo é sincronizado com a pasta de destino de fontes diferentes. Por exemplo, as estruturas de pastas podem ser assim:

fonte

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

(neste exemplo, a/a3.txte c/c1.txtsão sincronizados com o destino de outro lugar. Na prática, isso envolve várias outras fontes e o conteúdo/processos destas não podem ser influenciados.)

Agora diga que a pasta de origem exclui o a/a2.txtarquivo. Usando a configuração existente, este arquivo não seria excluído no destino; mas o uso --deleteresultaria na exclusão de outros arquivos e é um requisito não fazer isso.

Como poderia --deleteser usado neste rsync, mas atender ao requisito? Como o diretório de origem é controlado por versão, é bastante simples obter um antes e depois desse diretório, portanto, um backup diferencial pode ser calculado usando o diretório de origem original como referência, mas essa é a melhor maneira?

Responder1

Você não pode usar rsync --deleteassim. Não tem estado e não mantém registro de quais arquivos foram excluídos entre as execuções. O --deletesinalizador simplesmente instrui rsynca excluir todos os arquivos do destino que não existem na origem.

Para implementar essa exclusão restrita, acho que você precisa manter seu próprio estado. Nem rsyncnem unisonpode fazer isso por você.

O seguinte não é uma solução totalmente à prova de erros; é um ponto de partida. (No entanto, ele lida com arquivos com nomes estranhos - incluindo aqueles que contêm uma nova linha incorporada.)

Suponha que dois diretórios srce dst. (Para efeitos do exemplo, realmente não importa se dsté local ou 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 realizarmos um backup, execute o seguinte 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

Se a sua versão comm(como a minha) for anterior ao GNU coreutils 8.25 e não tiver o -zsinalizador, você poderá usar esta solução 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 realizarmos um backup, execute o seguinte 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

informação relacionada