rsync copia apenas certos tipos de arquivos usando a opção de inclusão

110

Eu uso o seguinte script bash para copiar apenas arquivos de certa extensão (neste caso * .sh), no entanto, ele ainda copia todos os arquivos. o que há de errado?

de = $ 1
para = $ 2

rsync -zarv --include = "*. sh" $ de $ a
user881480
fonte
4
Embora não seja estritamente relacionado, sugiro citar $ from / $ to. Não fazer isso pode gerar resultados inesperados se os argumentos posicionais 1/2 incluírem espaços.
Kjetil Joergensen de
você entendeu por que seu comando simplesmente não funcionava?
Charlie Parker
@CharlieParker: Você tem que usar rsync, isso pode muito bem ser conseguido com os internos do shell?
Inian
O que essa pergunta e suas respostas também carecem é como criar o comando se eu tiver diretórios recursivos para os quais desejo enviar apenas um tipo de arquivo. Parece que só faz isso para o diretório de destino ...
Charlie Parker

Respostas:

198

Acho que --includeé usado para incluir um subconjunto de arquivos que são excluídos por --exclude, em vez de incluir apenas esses arquivos. Em outras palavras: você tem que pensar em incluir significado , não excluir .

Em vez disso, tente:

rsync -zarv  --include "*/" --exclude="*" --include="*.sh" "$from" "$to"

Para rsync versão 3.0.6 ou superior, o pedido precisa ser modificado da seguinte forma (veja os comentários):

rsync -zarv --include="*/" --include="*.sh" --exclude="*" "$from" "$to"

Adicionar o -msinalizador evitará a criação de estruturas de diretório vazias no destino. Testado na versão 3.1.2.

Portanto, se quisermos apenas arquivos * .sh, temos que excluir todos os arquivos --exclude="*", incluir todos os diretórios --include="*/"e incluir todos os arquivos * .sh --include="*.sh".

Você pode encontrar alguns bons exemplos na seção Regras de padrão de inclusão / exclusão da página do manual

chepner
fonte
10
Embora ele forneça a você todos os subdiretórios, se houver algum arquivo .sh nos subdiretórios que deseja fazer rsync, é provável que você queira usar --include = "* /" também.
Kjetil Joergensen de
50
Eu tentei isso no rsync versão 3.0.7, que peguei há muito tempo no macports, e não funcionou com essa ordem de inclusões / exclusões. Isto é o que eu acabei com que funcionou para mim (adaptado para OP): rsync -zarv --include="*/" --include="*.sh" --exclude="*" "$from" "$to".
Bijou Trouvaille
3
Tentei com o rsync 3.0.9 e não funcionou. Bijou está certo, a ordem não é adequada (primeiro, --include=\*.shentão --exclude=\*)
TrueY
3
Observe que você sempre pode clicar em editar e sugerir uma edição para a resposta :)
Achal Dave
2
Não funciona com o seu pedido de inclui / exclui, mas funciona com o pedido sugerido por Bijou Trouvaille
John Smith Opcional
56

A resposta de @chepner irá copiar todos os subdiretórios independentemente do fato de conterem o arquivo ou não. Se você precisar excluir os subdiretórios que não contêm o arquivo e ainda retêm a estrutura do diretório, use

rsync -zarv  --prune-empty-dirs --include "*/"  --include="*.sh" --exclude="*" "$from" "$to"
WanderingMind
fonte
1
Este foi um requisito para mim: "Se você precisar excluir os subdiretórios que não contêm o arquivo e ainda reter a estrutura do diretório" +1
Juuso Ohtonen
1
Não entendo como você sabia qual era a ordem dos --includes?
Charlie Parker
1
Como criar o comando se tenho diretórios recursivos para os quais desejo enviar apenas um tipo de arquivo. Parece que só faz isso para o diretório de destino.
Charlie Parker de
15

Mais uma adição: se você precisar sincronizar arquivos por suas extensões em um único diretório (sem recursão), você deve usar uma construção como esta:

rsync -auzv --include './' --include '*.ext' --exclude '*' /source/dir/ /destination/dir/

Preste atenção ao ponto no primeiro --include. --no-rnão funciona nesta construção.

EDITAR:

Obrigado a gbyte.co pelo valioso comentário!

Serge Roussak
fonte
1
como você sabia qual deveria ser a ordem das bandeiras e o que elas deveriam incluir?
Charlie Parker
1
@CharlieParker, porque o rsync usa o includee as excludeopções na ordem que eles foram especificados. Além disso, ele pára em um primeiro correspondido. Portanto, se especificarmos --exclude '*'no primeiro lugar neste exemplo, o rsync não fará nada. Veja o homem para mais explicações.
Serge Roussak de
você pode me explicar o que cada bandeira está fazendo? O primeiro sinalizador -- include './' indica incluir tudo no caminho do diretório de origem? Então o próximo `--include '.ext'` inclui o arquivo específico no caminho de origem nomeado .exte então o exclude diz não enviar mais nada --exclude '*'? Isso é correto?
Charlie Parker
1
Como criar o comando se tenho diretórios recursivos para os quais desejo enviar apenas um tipo de arquivo. Parece que só faz isso para o diretório de destino.
Charlie Parker
1
Obrigado por isso! Precisa --include '*.ext'e não--include '.ext'
gbyte
13

Aqui está a parte importante da página de manual:

Conforme a lista de arquivos / diretórios a serem transferidos é construída, o rsync verifica cada nome a ser transferido em relação à lista de padrões de inclusão / exclusão, por sua vez, e o primeiro padrão correspondente é acionado: se for um padrão de exclusão, então esse arquivo é pulado; se for um padrão de inclusão, o nome do arquivo não será ignorado; se nenhum padrão correspondente for encontrado, o nome do arquivo não será ignorado.

Para resumir:

  • Não corresponder a nenhum padrão significa que um arquivo será copiado!
  • O algoritmo fecha assim que qualquer padrão coincide

Além disso, algo que termina com uma barra está combinando com os diretórios (como find -type d faria).

Vamos separar essa resposta de cima.

rsync -zarv  --prune-empty-dirs --include "*/"  --include="*.sh" --exclude="*" "$from" "$to"
  1. Não pule nenhum diretório
  2. Não pule nenhum .sh arquivo
  3. Pular tudo
  4. (Implicitamente, não pule nada, mas a regra acima impede que a regra padrão aconteça.)

Finalmente, o --prune-empty-directoriesimpede que a primeira regra crie diretórios vazios em todos os lugares.

Jim Hunziker
fonte
Muito obrigado por explicar o que está acontecendo. Agora há uma chance muito melhor de eu não esquecer o comando.
MohamedEzz
3
'' O algoritmo é encerrado assim que qualquer padrão corresponde " - esta é a chave, e nenhuma das respostas com classificação mais alta o explica de forma tão clara e direta como você fez aqui. Claro que isso está na página de manual em algum lugar, e se eu leria tudo com cuidado, eu teria visto. Ainda assim, obrigado.
TheDudeAbides
0

Se alguém procurar por isso ... Queria rsync apenas arquivos e pastas específicos e consegui fazer com este comando: rsync --include-from=rsync-files

Com arquivos rsync:

my-dir/
my-file.txt

- /*
Pascal Polleunus
fonte
0

Escrevi esta função útil e coloquei em meus scripts bash ou ~/.bash_aliases. Sincronização testada localmente no Linux com bash e awkinstalada. Funciona

selrsync(){
# selective rsync to sync only certain filetypes;
# based on: https://stackoverflow.com/a/11111793/588867
# Example: selrsync 'tsv,csv' ./source ./target --dry-run
types="$1"; shift; #accepts comma separated list of types. Must be the first argument.
includes=$(echo $types| awk  -F',' \
    'BEGIN{OFS=" ";}
    {
    for (i = 1; i <= NF; i++ ) { if (length($i) > 0) $i="--include=*."$i; } print
    }')
restargs="$@"

echo Command: rsync -avz --prune-empty-dirs --include="*/" $includes --exclude="*" "$restargs"
eval rsync -avz --prune-empty-dirs --include="*/" "$includes" --exclude="*" $restargs
}

Avantages:

curto, prático e extensível quando se deseja adicionar mais argumentos (ou seja --dry-run).

Exemplo:

selrsync 'tsv,csv' ./source ./target --dry-run
biocyberman
fonte