
Eu tenho um rsync
processo 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.txt
e c/c1.txt
sã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.txt
arquivo. Usando a configuração existente, este arquivo não seria excluído no destino; mas o uso --delete
resultaria na exclusão de outros arquivos e é um requisito não fazer isso.
Como poderia --delete
ser 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 --delete
assim. Não tem estado e não mantém registro de quais arquivos foram excluídos entre as execuções. O --delete
sinalizador simplesmente instrui rsync
a 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 rsync
nem unison
pode 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 src
e 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 -z
sinalizador, 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