rsync certos arquivos, excluindo o resto, ignorando o diretório .svn /, recursivamente

16

Estou usando rsync para copiar alguns arquivos de um compartilhamento para outro.

Recursivamente, eu preciso:

  • Excluir arquivos no destino que foram removidos da origem
  • Apenas sincronize .php e .js arquivos
  • Excluir todos os outros tipos de arquivo
  • Não exclua .svn/ diretórios no destino

Se eu usar isso:

rsync -zavC --delete --include='*.php' --include='*.js' --exclude="*" \
    /origin /destination

Em seguida, rsync não é recursivo porque exclude="*" exclui todos os arquivos, mas também as pastas.

Se eu adicionar --include="*/" , o diretório .svn/ será excluído (ele também será incluído).

Como posso resolver esse dilema de explosão mental?

uname -a :

Linux tux 3.9.2-1-ARCH #1 SMP PREEMPT Sat May 11 20:31:08 CEST 2013 x86_64 GNU/Linux

rsync versão:

rsync 3.0.9-6
    
por canolucas 17.05.2013 / 21:38

2 respostas

12

1ª tentativa (não funcionou)

Você precisa incluir os diretórios, além dos arquivos:

rsync -zavC --delete --include '*/' --include='*.php' --include='*.js' \
     --exclude="*" /media/datacod/Test/ /home/lucas/Desktop/rsync/

2ª tentativa

rsync -avzC --filter='-rs_*/.svn*' --include="*/" --include='*.js' \
     --include='*.php' --exclude="*" --delete dir1/ dir2/

dados de teste

Eu escrevi esse script para criar alguns dados de amostra para testar isso. Aqui está esse script, setup_svn_sample.bash :

#!/bin/bash

# setup .svn dirs
mkdir -p dir{1,2}/dir{1,2,3,4}/.svn

# fake data under .svn
mkdir -p dir1/dir{1,2,3,4}/.svn/origdir
mkdir -p dir2/dir{1,2,3,4}/.svn/keepdir

# files to not sync
touch dir1/dir{1,2,3,4}/file{1,2}

# files to sync
touch dir1/dir{1,2,3,4}/file1.js
touch dir1/dir{1,2,3,4}/file1.php

A execução produz os seguintes diretórios:

dir de origem

$ tree -a dir1
dir1
|-- dir1
|   |-- file1
|   |-- file1.js
|   |-- file1.php
|   |-- file2
|   '-- .svn
|       '-- origdir
|-- dir2
|   |-- file1
|   |-- file1.js
|   |-- file1.php
|   |-- file2
|   '-- .svn
|       '-- origdir
|-- dir3
|   |-- file1
|   |-- file1.js
|   |-- file1.php
|   |-- file2
|   '-- .svn
|       '-- origdir
'-- dir4
    |-- file1
    |-- file1.js
    |-- file1.php
    |-- file2
    '-- .svn
        '-- origdir

dir de destino

$ tree -a dir2
dir2
|-- dir1
|   '-- .svn
|       '-- keepdir
|-- dir2
|   '-- .svn
|       '-- keepdir
|-- dir3
|   '-- .svn
|       '-- keepdir
'-- dir4
    '-- .svn
        '-- keepdir

Executando o comando rsync acima:

rsync -avzC --filter='-rs_*/.svn*' --include="*/" --include='*.js' \
     --include='*.php' --exclude="*" --delete dir1/ dir2/
sending incremental file list
dir1/file1.js
dir1/file1.php
dir2/file1.js
dir2/file1.php
dir3/file1.js
dir3/file1.php
dir4/file1.js
dir4/file1.php

sent 480 bytes  received 168 bytes  1296.00 bytes/sec
total size is 0  speedup is 0.00

Resultado final dir2:

$ tree -a dir2
dir2
|-- dir1
|   |-- file1.js
|   |-- file1.php
|   '-- .svn
|       '-- keepdir
|-- dir2
|   |-- file1.js
|   |-- file1.php
|   '-- .svn
|       '-- keepdir
|-- dir3
|   |-- file1.js
|   |-- file1.php
|   '-- .svn
|       '-- keepdir
'-- dir4
    |-- file1.js
    |-- file1.php
    '-- .svn
        '-- keepdir

Por que isso funciona?

A peça-chave deste script é usar o recurso de filtros de rsync . Os filtros permitem remover arquivos do conjunto correspondente em vários pontos do comando. Então, no nosso caso, estamos filtrando todos os arquivos que correspondem ao padrão */.svn* . Os modificadores -rs_ informam ao filtro que queremos filtrar tanto no lado da origem quanto no lado do destino.

trecho da seção FILTER NOTES da página man do rsync

  • An s is used to indicate that the rule applies to the sending side. When a rule affects the sending side, it prevents files from being transferred. The default is for a rule to affect both sides unless --delete-excluded was specified, in which case default rules become sender-side only. See also the hide (H) and show (S) rules, which are an alternate way to specify sending-side includes/excludes.

  • An r is used to indicate that the rule applies to the receiving side. When a rule affects the receiving side, it prevents files from being deleted. See the s modifier for more info. See also the protect (P) and risk (R) rules, which are an alternate way to specify receiver-side includes/excludes.

Veja man rsync para mais detalhes.

Dicas para descobrir isso (sugestão usando --dry-run )

Ao descrever como fazer isso, pensei em mencionar a opção --dry-run para rsync . É extremamente útil ver o que acontecerá sem que o rsync realmente ocorra.

Por exemplo

Usar o seguinte comando fará um teste e mostrará a lógica de decisão por trás de rsync :

rsync --dry-run -avvzC --filter='-rs_*/.svn*' --include="*/" \
     --include='*.js' --include='*.php' --exclude="*" --delete dir1/ dir2/
sending incremental file list
[sender] showing directory dir3 because of pattern */
[sender] showing directory dir2 because of pattern */
[sender] showing directory dir4 because of pattern */
[sender] showing directory dir1 because of pattern */
[sender] hiding file dir1/file1 because of pattern *
[sender] showing file dir1/file1.js because of pattern *.js
[sender] hiding file dir1/file2 because of pattern *
[sender] showing file dir1/file1.php because of pattern *.php
[sender] hiding directory dir1/.svn because of pattern */.svn*
[sender] hiding file dir2/file1 because of pattern *
[sender] showing file dir2/file1.js because of pattern *.js
[sender] hiding file dir2/file2 because of pattern *
[sender] showing file dir2/file1.php because of pattern *.php
[sender] hiding directory dir2/.svn because of pattern */.svn*
[sender] hiding file dir3/file1 because of pattern *
[sender] showing file dir3/file1.js because of pattern *.js
[sender] hiding file dir3/file2 because of pattern *
[sender] showing file dir3/file1.php because of pattern *.php
[sender] hiding directory dir3/.svn because of pattern */.svn*
[sender] hiding file dir4/file1 because of pattern *
[sender] showing file dir4/file1.js because of pattern *.js
[sender] hiding file dir4/file2 because of pattern *
[sender] showing file dir4/file1.php because of pattern *.php
[sender] hiding directory dir4/.svn because of pattern */.svn*
delta-transmission disabled for local transfer or --whole-file
[generator] risking directory dir3 because of pattern */
[generator] risking directory dir2 because of pattern */
[generator] risking directory dir4 because of pattern */
[generator] risking directory dir1 because of pattern */
[generator] protecting directory dir1/.svn because of pattern */.svn*
dir1/file1.js
dir1/file1.php
[generator] protecting directory dir2/.svn because of pattern */.svn*
dir2/file1.js
dir2/file1.php
[generator] protecting directory dir3/.svn because of pattern */.svn*
dir3/file1.js
dir3/file1.php
[generator] protecting directory dir4/.svn because of pattern */.svn*
dir4/file1.js
dir4/file1.php
total: matches=0  hash_hits=0  false_alarms=0 data=0

sent 231 bytes  received 55 bytes  572.00 bytes/sec
total size is 0  speedup is 0.00 (DRY RUN)

Na saída acima, você pode ver que os diretórios ./svn estão sendo protegidos por nossa regra de filtragem. Insight valioso para depurar o rsync .

Referências

por 17.05.2013 / 21:59
9

Ok, depois de várias tentativas, resolvi isso:

rsync -vaiz --delete --exclude=.svn/ --include='*.php' --include='*.js' \
    --include='*/' --exclude='*' --prune-empty-dirs \
    --filter "protect .svn/" /origin /destination

Obrigado

    
por 18.05.2013 / 01:19