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 ...
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:
--exclude=*~
, --exclude=/some/relative/location
(relativo ao argumento de origem, por exemplo, isso exclui ~/LaTeX/some/relative/location
).--include=*/
) e exclua o restante com --exclude='*'
. Isto é porque:--include='directory/***'
fará isso.Padrões:
/
, aplica-se ao nome do arquivo sans directory./
, aplica-se apenas a diretórios./
, 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/
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 '*'.
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/
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.
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:
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
...)
Falha e potencialmente produzindo um erro em vez de executar o comando (como você descobriu o zsh por padrão).
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
Que tal agora:
rsync -avn --include="*.pdf" ~/Latex/ ~/Output/
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.
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