it-swarm-pt.tech

Filtro Rsync: copiando apenas um padrão

Estou tentando criar um diretório que abrigue todos e apenas meus PDFs compilados a partir do LaTeX. Eu gosto de manter cada projeto em uma pasta separada, todos alojados em uma grande pasta chamada LaTeX. Então eu tentei correr:

rsync -avn *.pdf ~/LaTeX/ ~/Output/

que deve encontrar todos os pdfs em ~/LaTeX/ e transfira-os para a pasta de saída. Isso não funciona. Diz-me que não foi encontrado nenhum resultado para "*.pdf ". Se eu deixar de fora esse filtro, o comando listará todos os arquivos em todas as pastas do projeto no LaTeX. Portanto, há um problema com o filtro * .pdf. Tentei substituir ~/ com o caminho completo para o meu diretório pessoal, mas isso não teve efeito.

Estou usando o zsh. Eu tentei fazer a mesma coisa no bash e até com o filtro que listava todos os arquivos em todos os subdiretórios ... O que está acontecendo aqui?

Por que o rsync não está entendendo meu filtro apenas de pdf?


ESTÁ BEM. Então atualize: Não, estou tentando

rsync -avn --include="*/" --include="*.pdf" LaTeX/ Output/

E isso me dá toda a lista de arquivos. Eu acho que porque tudo corresponde ao primeiro padrão ...

142
Seamus

TL, DR:

rsync -am --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/

Rsync copia a (s) fonte (s) para o destino. Se você passar *.pdf como fontes, o Shell expande isso para a lista de arquivos com os .pdf extensão no diretório atual. Nenhuma passagem recursiva acontece porque você não passou nenhum diretório como fonte.

Então você precisa executar rsync -a ~/LaTeX/ ~/Output/, mas com um filtro para solicitar ao rsync que copie .pdf apenas arquivos. As regras de filtro do Rsync podem parecer assustadoras quando você lê o manual, mas você pode criar muitos exemplos com apenas algumas regras simples.

  • Inclusões e exclusões:

    • A exclusão de arquivos por nome ou local é fácil: --exclude=*~, --exclude=/some/relative/location (relativo ao argumento de origem, por exemplo, isso exclui ~/LaTeX/some/relative/location).
    • Se você deseja corresponder apenas a alguns arquivos ou locais, inclua-os, inclua todos os diretórios que os levam (por exemplo, com --include=*/) e exclua o restante com --exclude='*'. Isto é porque:
    • Se você excluir um diretório, isso excluirá tudo abaixo dele. Os arquivos excluídos não serão considerados.
    • Se você incluir um diretório, isso não incluirá automaticamente seu conteúdo. Nas versões recentes, --include='directory/***' fará isso.
    • Para cada arquivo, a primeira regra correspondente se aplica (e qualquer coisa nunca correspondida é incluída).
  • Padrões:

    • Se um padrão não contiver um /, aplica-se ao nome do arquivo sans directory.
    • Se um padrão terminar com /, aplica-se apenas a diretórios.
    • Se um padrão começar com /, aplica-se a todo o caminho do diretório que foi passado como argumento para rsync.
    • * qualquer substring de um único componente de diretório (ou seja, nunca corresponde a /); ** corresponde a qualquer substring de caminho.
  • Se um argumento de origem terminar com um /, seu conteúdo é copiado (rsync -r a/ b cria b/foo para cada a/foo). Caso contrário, o próprio diretório é copiado (rsync -r a b cria b/a).


Portanto, aqui precisamos incluir *.pdf, inclua diretórios que os contenham e exclua todo o resto.

rsync -a --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/

Observe que isso copia todos os diretórios, mesmo aqueles que não contêm arquivos ou subdiretórios correspondentes. Isso pode ser evitado com o --Prune-empty-dirs opção (não é uma solução universal, pois você não pode copiar um diretório nem mesmo combiná-lo explicitamente, mas esse é um requisito raro).

rsync -am --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/
274
rsync -av --include="*/" --include="*.pdf" --exclude="*" ~/Latex/ ~/Output/ --dry-run

O padrão é incluir tudo, portanto, você deve excluir explicitamente tudo depois incluindo os arquivos que deseja transferir. Remova o --dry-run para realmente transferir os arquivos.

Se você começar com:

--exclude '*' --include '*.pdf'

A correspondência gananciosa excluirá tudo imediatamente.

Se você tentar:

--include '*.pdf' --exclude '*' 

Somente os arquivos pdf na pasta de nível superior serão transferidos. Ele não seguirá nenhum diretório, pois esses são excluídos por '*'.

30
jmanning2k

Se você usar um padrão como *.pdf, o Shell "expande" esse padrão, ou seja, substitui o padrão por todas as correspondências no diretório atual. O comando que você está executando (neste caso, rsync) não tem conhecimento do fato de que você tentou usar um padrão.

Quando você está usando zsh, existe uma solução fácil: O ** padrão pode ser usado para corresponder pastas recursivamente. Tente o seguinte:

rsync -avn ~/LaTeX/**/*.pdf ~/Output/
15
Marcel Stimberg

Você pode usar find e uma lista intermediária de arquivos (files_to_copy) para resolver seu problema. Verifique se você está no diretório inicial e, em seguida:

find LaTeX/ -type f -a -iname "*.pdf" > files_to_copy && rsync -avn --files-from=files_to_copy ~/ ~/Output/ && rm files_to_copy

Testado com Bash.

13
Derek Frye

A julgar pela seção "INCLUIR/EXCLUIR REGRAS DE PADRÃO" da página de manual , a maneira de fazer isso é

rsync -avn --include="*/" --include="*.pdf" ~/Latex/ ~/Output/

A diferença crítica entre esta e a resposta do kbrd é a --include="*/" flag, que diz ao rsync para seguir em frente e copiar todos os diretórios encontrados, independentemente do nome. Isso é necessário porque o rsync não recursará em um subdiretório, a menos que tenha sido instruído a copiar esse subdiretório.

Além disso, observe que as aspas impedem que o Shell tente expandir os padrões para nomes de arquivos em relação ao diretório atual e siga um destes procedimentos:

  1. Sucesso e bagunçar o filtro (não é muito provável no meio de uma bandeira como essa, embora você nunca saiba quando alguém criará um arquivo chamado --include=foo.pdf ...)

  2. Falha e potencialmente produzindo um erro em vez de executar o comando (como você descobriu o zsh por padrão).

9
SamB

Esta é a minha solução preferida:

find source_dir -iname '*.jpg' -print0 |  rsync -0 -v --files-from=- . destination_dir/

O comando find é mais fácil de entender do que as regras de inclusão/exclusão de rsync :-)

Se você deseja copiar apenas arquivos pdf, basta alterar .jpg para .pdf

3
guettli

Que tal agora:

rsync -avn --include="*.pdf" ~/Latex/ ~/Output/
3
kbyrd

Aqui está algo que deve funcionar sem usar o find. A diferença das respostas já postadas é a ordem das regras de filtro. As regras de filtro em um comando rsync funcionam muito como as regras do iptable, a primeira regra que um arquivo corresponde é a usada. Do página de manual :

À medida que a lista de arquivos/diretórios a serem transferidos é criada, o rsync verifica cada nome a ser transferido à 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, esse arquivo será pulado; se for um padrão de inclusão, esse nome de arquivo não será ignorado; se nenhum padrão correspondente for encontrado, o nome do arquivo não será ignorado.

Portanto, você precisa de um comando da seguinte maneira:

rsync -avn --include="**.pdf" --exclude="*" ~/LaTeX/ ~/Output/

Observe o padrão "**. Pdf". De acordo com a página de manual :

se o padrão contiver um/(sem contar um/final) ou um "**", será comparado com o nome do caminho completo, incluindo todos os diretórios principais. Se o padrão não contiver um/ou "**", será comparado apenas com o componente final do nome do arquivo. (Lembre-se de que o algoritmo é aplicado recursivamente para que "nome completo do arquivo" possa realmente ser qualquer parte de um caminho do diretório inicial para baixo

No meu pequeno teste, isso funciona recursivamente na árvore de diretórios e seleciona apenas os pdfs.

2
Steven D

Para gerar um diretório contendo apenas cabeçalhos (../include) de dentro do diretório de origem:

rsync -avh --Prune-empty-dirs --exclude="build" --include="*/" --include="*.h" --exclude="*" ./* ../include/

Isso exclui todos os diretórios vazios e o diretório build

0
SCG82