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

19

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

Recursivamente, eu preciso:

  • Excluir arquivos no destino que foram removidos da origem
  • Somente sincronização .phpe .jsarquivos
  • Excluir qualquer outro tipo de arquivo
  • Não exclua .svn/diretórios no destino

Se eu usar isso:

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

Então rsyncnão é recursivo porque exclude="*"exclui todos os arquivos, mas também pastas.

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

Como posso resolver esse dilema de explodir a mente?

uname -a:

Linux tux 3.9.2-1-ARCH # 1 SMP PREEMPT Sáb 11 de maio 20:31:08 CEST 2013 x86_64 GNU / Linux

rsync versão:

rsync 3.0.9-6
canolucas
fonte

Respostas:

13

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 este script para criar alguns dados de amostra para testar isso. Aqui está o 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 rsynccomando 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

Dir2 resultante depois:

$ 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 parte principal desse script é usar o recurso de filtros do rsync. Os filtros permitem remover arquivos do conjunto correspondente em vários pontos do comando. Portanto, 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 fonte quanto no lado do destino.

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

  • Um s é usado para indicar que a regra se aplica ao lado de envio. Quando uma regra afeta o lado do envio, impede que os arquivos sejam transferidos. O padrão é que uma regra afete os dois lados, a menos que tenha --delete-excludedsido especificado. Nesse caso, as regras padrão se tornam apenas do lado do remetente. Consulte também as regras hide (H) e show (S), que são uma maneira alternativa de especificar as inclusões / exclusões do lado do envio.

  • Um r é usado para indicar que a regra se aplica ao lado receptor. Quando uma regra afeta o lado do recebimento, impede que os arquivos sejam excluídos. Veja o modificador s para mais informações. Consulte também as regras de proteção (P) e risco (R), que são uma maneira alternativa de especificar inclusões / exclusões do lado do receptor.

Veja man rsync para mais detalhes.

Dicas para descobrir isso (dica usando --dry-run)

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

Por exemplo

O uso do comando a seguir fará uma execução de teste e nos mostrará a lógica de decisão por trás 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 ./svndiretórios estão sendo protegidos por nossa regra de filtro. Informações valiosas para depurar o arquivo rsync.

Referências

slm
fonte
Já tentei isso, como eu disse acima. Se eu fizer isso, o diretório .SVN também será incluído (provavelmente excluído, porque ele não existe na origem ou modificado). É fundamental deixar o diretório .SVN intocado. Obrigado pela tentativa de qualquer maneira! :)
canolucas
-C deve ignorar ".SVN /", mas include="*/"inclui
canolucas
Você está certo. Deveria ser .svn, editando a resposta. Enfim, depois de renomear o problema permanece. -Ce include="*/"não parece ser um amigo muito próximo :(
canolucas 17/05
10

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

canolucas
fonte
Ótima resposta. Meu filtro protege os .svn/diretórios --prune-empty-dirscaso estejam vazios. Outra abordagem, esta duplicando dirs vazios:rsync -vaiz --delete --exclude=.svn/ --include='*.php' --include='*.js' --include='*/' --exclude='*' /origin /destination
canolucas 18/13
A chave da minha abordagem é --exclude=.svn/antes do --include's
canolucas
Boa resposta também. Eu sugeriria um exclude = '. Svn /', mas achei que você queria usar o -C. Fico feliz que você tenha entendido!
Slm
0

Embora isso não esteja usando o rsync, outra opção é usar o find e o cpio. Por exemplo, eu tenho um diretório chamado Fotos e que é o ano e o mês.

Photos
├── 2002
   ├── 2002-03
      ├── 2002-03-30
      ├── 2002-03-31
      └── 2002-03-31-02
   ├── 2002-04
      ├── 2002-04-01
      ├── 2002-04-01-03
      ├── 2002-04-07
      ├── 2002-04-21
      ├── 2002-04-22
      ├── 2002-04-22-02
      └── 2002-04-27
   ├── 2002-05
      ├── 2002-05-02
      ├── 2002-05-03

Mas aqui eu tenho jpg, dng, xml e outras coisas e quero apenas os jpgs para fazer isso

"cd" para o diretório acima do diretório Fotos, em seguida:

find Photos -type f -name "*jpg" -print | cpio -pdmvu /fast

E lá vai

/fast/Photos/2002/2002-04/2002-04-22/bath problem.jpg
/fast/Photos/2002/2002-04/2002-04-22-02/full bath.jpg
/fast/Photos/2002/2002-07/2002-07-10/Broken Top.jpg
/fast/Photos/2002/2002-12/2002-12-28/101-0125_IM~~G.jpg
/fast/Photos/2002/2002-12/2002-12-28/small-101-0125_IM~~G.jpg
/fast/Photos/2003/2003-01/2003-01-19/k1.jpg
/fast/Photos/2003/2003-01/2003-01-19/k2.jpg
/fast/Photos/2003/2003-02/2003-02-23/quinn.jpg
/fast/Photos/2003/2003-05/2003-05-04/all.jpg
/fast/Photos/2003/2003-05/2003-05-09/100_0015_r1.jpg
/fast/Photos/2003/2003-05/2003-05-09/100_0006_2_r1.jpg
/fast/Photos/2003/2003-05/2003-05-09/100_0006_r1.jpg
/fast/Photos/2003/2003-05/2003-05-09/100_0007_2_r1.jpg

Você pode usar esse método para muitas coisas; anos atrás, é assim que copiaríamos o sistema de arquivos / ao mover para discos maiores, como copiaria os arquivos do dispositivo.

lxtwin
fonte
Isso não responde à pergunta.
RalfFriedl 22/09
Isso acontece se ele usa: find / origin -type f (-name " .php" -o -name " .js") -print | cpio -pdmvu / destination Apenas os arquivos * .php e * .js estarão no diretório de destino.
lxtwin 23/09