Sincronize unidirecionalmente um diretório, mas deixe os arquivos apagados apagados no destino

6

Eu quero sincronizar um diretório entre dois sistemas. Para torná-lo mais interessante, a sincronização só deve ser feita em uma direção, por exemplo:

  • se um arquivo for excluído no diretório de origem, ele também deverá ser excluído no destino, se tiver sido transferido anteriormente
  • arquivos excluídos no diretório de destino não devem ser excluídos na origem
  • arquivos parcialmente transferidos (por exemplo, devido a problemas de rede) devem ser concluídos na próxima sincronização
  • novos arquivos no diretório de origem devem ser transferidos para o destino
  • arquivos excluídos no diretório de destino não devem ser transferidos

Isso significa que o sistema de origem tem basicamente uma função de mestre, exceto que os arquivos excluídos no destino não serão forçados a voltar.

Ambos os sistemas Linux têm o rsync / ssh / scp disponível.

Novos arquivos no diretório de origem são criados de forma que se possa usar o seu mtime para detectá-los, por exemplo:

if mtime(file) > date-of-last-sync then: it is a new file that needs to be transfered

Além disso, os arquivos existentes não são alterados no diretório de origem, ou seja, a sincronização não precisa verificar diferenças nos arquivos já transferidos (completamente).

    
por maxschlepzig 24.08.2014 / 10:56

3 respostas

1

Se você não for usar o sistema de arquivos remoto como a fonte de dados do que foi transferido, será necessário rastrear externamente os arquivos que foram transferidos com êxito anteriormente e, em seguida, excluí-los das transferências futuras.

rsync pode incluir e excluir arquivos baseados em padrões em um arquivo assim você pode incluir uma lista específica de arquivos em uma transferência. Em seguida, exclua essa lista das transferências futuras.

#!/usr/bin/env bash

set -e

track_dir=~/.track_xfer
inc_file="$track_dir/include_files"
exc_file="$track_dir/exclude_files"
xfer_dir=~/testrsync
xfer_dest=~/testrsync_dest

mkdir -p "$track_dir"
touch $exc_file
cd "$xfer_dir"

# find files and create rsync filter list
find . -type f -print0 | perl -e '
  $/="
#!/usr/bin/env bash

set -e

track_dir=~/.track_xfer
inc_file="$track_dir/include_files"
exc_file="$track_dir/exclude_files"
xfer_dir=~/testrsync
xfer_dest=~/testrsync_dest

mkdir -p "$track_dir"
touch $exc_file
cd "$xfer_dir"

# find files and create rsync filter list
find . -type f -print0 | perl -e '
  $/="%pre%"; 
  while (<>){ 
   chomp; 
   $_ =~ s!^\.!!;    # remove leading .
   $f = quotemeta;   # quote special chars
   $f =~ s!\/!/!g;  # fix quoted paths '/'
   print $f."\n"; 
  }' > "$inc_file"

# Run the rsync
rsync -va --delete --exclude-from "$exc_file" --include-from "$inc_file" "$xfer_dir/" "$xfer_dest"

# Add the included/transferred files to the exclusion list
cat "$inc_file" "$exc_file" > "$exc_file".tmp
sort "$exc_file".tmp | uniq > "$exc_file"
"; while (<>){ chomp; $_ =~ s!^\.!!; # remove leading . $f = quotemeta; # quote special chars $f =~ s!\/!/!g; # fix quoted paths '/' print $f."\n"; }' > "$inc_file" # Run the rsync rsync -va --delete --exclude-from "$exc_file" --include-from "$inc_file" "$xfer_dir/" "$xfer_dest" # Add the included/transferred files to the exclusion list cat "$inc_file" "$exc_file" > "$exc_file".tmp sort "$exc_file".tmp | uniq > "$exc_file"

Você pode precisar de mais algumas citações em regex específicas em rsync , mas a função Perl quotemeta e suas substituições foi a primeira solução fácil que me veio à mente.

O principal problema será lidar com qualquer caractere especial em nomes de arquivos. Se você quer lidar com novas linhas ou abas e outras coisas estranhas nos nomes, então você terá que colocar um pouco mais de trabalho no perl (ou qualquer outro) que analise e gere a lista de padrões de inclusão. Se você puder restringir os nomes de seus arquivos de transferência a um conjunto de caracteres simples, não precisará se preocupar com essa etapa. O perl é uma solução incompleta que deve fazer com que você ultrapasse os caracteres regex mais comuns.

O motivo para usar a lista de inclusão, em vez de permitir que rsync puxe o próprio diretório inteiro, é para que você tenha uma lista definida / completa de arquivos para a lista de exclusões subsequente. Você provavelmente poderia obter o mesmo resultado analisando a rsync output ou a --log-file=FILE dos arquivos que foram transferidos, mas isso pareceu um pouco mais difícil.

    
por 24.08.2014 / 18:51
-1

O Rsync fará exatamente o que você deseja com rsync -a --delete (adicione -x se você precisar de xattrs, por exemplo, para o selinux).

O rsync nunca excluirá arquivos na origem, mas --delete excluirá todos os arquivos no destino que não existem na origem.

Ele atualizará os arquivos parcialmente transferidos pelo mecanismo de atualização delta. AFAIR rsync verificará o mtime (+ tamanho do arquivo) primeiro e somente se houver uma incompatibilidade, a impressão digital e a delta-atualização serão feitas.

    
por 24.08.2014 / 12:47
-1

Por favor, leia a man page, pois ela deve responder a todas as suas perguntas. O comando man rsync deve exibir a página man.

O rsync verificará se os arquivos não foram alterados. É extremamente eficiente em fazer isso e nunca diminuiu significativamente os tempos de rsync para minhas transferências. Você pode estimar o tempo que levará ao sincronizar uma execução do rsync imediatamente após a última execução.

O rsync é uma sincronização unidirecional e não altera a origem. Você pode usar com segurança um ID do usuário que só pode ler o arquivo de origem, mas não possui privilégios de gravação. No entanto, isso não é necessário.

O rsync recuperará todas as transferências parcialmente concluídas quando você executá-las novamente.

O rsync só excluirá arquivos nos destinos se você usar uma das opções de exclusão.

EDIT: Para evitar a transferência de arquivos excluídos do diretório de destino, você precisa criar uma lista de exclusão para esses arquivos. Isso os excluirá das transferências, mesmo que sejam atualizadas. Como alternativa, você pode truncar os arquivos em vez de excluí-los e usar o sinalizador --update . Arquivos que são atualizados depois que você os truncar serão copiados.

Você pode achar que um usando um backup tar incremental faz o que você quer melhor. É possível usar pipe a saída de um tar para outro através de uma conexão ssh. Isso selecionará todos os arquivos criados ou modificados desde o último backup, mas não transferirá nenhum outro arquivo.

    
por 24.08.2014 / 19:57