rsync usando regex para incluir apenas alguns arquivos

11

Estou tentando executar o rsync para copiar alguns arquivos recursivamente por um caminho baseado no padrão de nome de arquivo, caso insensível . Isto é o que eu fiz para executar o rsync:

$ rsync -avvz --include ='*/' --include='.*[Nn][Aa][Mm][E].*' --exclude='*' ./a/ ./b/

Nada é copiado, a saída de depuração mostra:

[sender] hiding file 1Name.txt because of pattern *
[sender] hiding file 1.txt because of pattern *
[sender] hiding file 2.txt because of pattern *
[sender] hiding file Name1.txt because of pattern *
[sender] hiding directory test1 because of pattern *
[sender] hiding file NaMe.txt because of pattern *

Eu tentei usar: --include='*[Nn][Aa][Mm][E]*' e outras combinações, mas ainda não funciona.

Alguma idéia de como usar o regex para incluir alguns arquivos?

    
por user1957413 14.01.2013 / 11:22

6 respostas

5

O rsync não fala regex. Você pode inscrever o find e o grep, embora fique um pouco misterioso. Para encontrar os arquivos de destino:

find a/ |
grep -i 'name'

Mas todos eles são prefixados com "a /" - o que faz sentido, mas o que queremos é uma lista de padrões de inclusão aceitável para o rsync, e como o prefixo "a /" não funciona rsync eu vou removê-lo com o corte:

find . |
grep -i 'name' |
cut -d / -f 2-

Ainda há um problema - ainda vamos sentir falta de arquivos em subdiretórios, porque o rsync não pesquisa diretórios na lista de exclusão. Vou usar o awk para adicionar os subdiretórios de quaisquer arquivos correspondentes à lista de padrões de inclusão:

find a/ |
grep -i 'name' |
cut -d / -f 2- |
awk -F/ '{print; while(/\//) {sub("/[^/]*$", ""); print}}'

Tudo o que resta é enviar a lista para o rsync - podemos usar o argumento --include-from = - para fornecer uma lista de padrões para o rsync na entrada padrão. Então, ao todo:

find a/ |
grep -i 'name' |
cut -d / -f 2- |
awk -F/ '{print; while(/\//) {sub("/[^/]*$", ""); print}}' |
rsync -avvz --include-from=- --exclude='*' ./a/ ./b/

Observe que o diretório de origem 'a' é referido por dois caminhos diferentes - "a /" e "./a/". Isso é sutil, mas importante. Para tornar as coisas mais consistentes, farei uma alteração final e sempre me refiro ao diretório de origem como "./a/". No entanto, isso significa que o comando de corte deve ser alterado, pois haverá um "./" extra na frente dos resultados de find:

find ./a/ |
grep -i 'name' |
cut -d / -f 3- |
awk -F/ '{print; while(/\//) {sub("/[^/]*$", ""); print}}' |
rsync -avvz --include-from=- --exclude='*' ./a/ ./b/
    
por 15.01.2013 / 03:30
6

Eu sugiro usar a opção de filtro do rsync. Para o seu exemplo, basta digitar:

rsync -vam -f'+ *[Nn][Aa][Mm][E]*' -f'+ */' -f'- *' a b

a primeira regra de filtragem informa ao rsync quais padrões devem ser incluídos. A segunda regra é necessária para informar ao rsync para inspecionar todos os diretórios em sua passagem. Para impedir que dirs vazios sejam incluídos, eles são excluídos explicitamente pela opção -m . A última regra de filtragem diz ao rsync para descartar todos os padrões restantes que ainda não foram encontrados.

    
por 15.01.2013 / 18:48
1

Se você usar o ZSH, poderá usar o sinalizador (#i) para desativar a diferenciação de maiúsculas e minúsculas. Exemplo:

$ touch NAME
$ ls (#i)*name*
NAME

O ZSH também suporta exclusões, que são especificadas como o caminho normal, mas elas têm uma inicial

$ touch aa ab ac
$ ls *~*c
aa ab

Você pode encadear exclusões:

$ ls *~*c~*b
aa

Por fim, você pode especificar o tipo de arquivo que deseja retornar (diretório, arquivo, etc). Isso é feito com (/) para o diretório e (.) Para o arquivo.

$ touch file
$ mkdir dir
$ ls *(.)
file

Com base em tudo isso, eu faria esse comando como:

rsync -avvz *(/) (#i)*name* ./a/ ./b/

(não vejo necessidade de uma exclusão com esses seletores)

    
por 30.01.2013 / 23:35
1

@ A resposta da sqweek acima é incrível, embora eu suspeite que ele tenha um bug em seu script awk para gerar diretórios-pais, como me dá, por exemplo:

$ echo a/b/c/d | awk -F/ '{print; while(/\//) {sub("/[^/]*", ""); print}}'
a/b/c/d
a/c/d
a/d
a

Consegui corrigi-lo usando gensub :

$ echo a/b/c/d | awk -F/ '{print; while(/\//) { $0=gensub("(.*)/[^/]*", "\1", "g"); print}}'
a/b/c/d
a/b/c
a/b
a

Assim, sua solução completa, com o awk alterado, seria:

find ./a/ |
grep -i 'name' |
cut -d / -f 3- |
awk -F/ '{print; while(/\//) { $0=gensub("(.*)/[^/]*", "\1", "g"); print}}' |
rsync -avvz --include-from=- --exclude='*' ./a/ ./b/
    
por 07.01.2015 / 02:57
0

Tentei usar um script em C #, pois é o idioma com o qual tenho mais experiência. Eu sou capaz de criar a lista de arquivos que eu quero incluir, mas alguém rsync ainda me diz para fazer uma caminhada. Cria as pastas, mas ignora os arquivos. Aqui está o que eu tenho ..

Primeiro, o conteúdo do diretório:

~/mono$ ls -l
total 24
drwxr-xr-x 5 me me 4096 Jan 15 00:36 a
drwxr-xr-x 2 me me 4096 Jan 15 00:36 b
drwxr-xr-x 3 me me 4096 Jan 14 00:31 bin
-rw-r--r-- 1 me me 3566 Jan 15 00:31 test.cs
-rwxr-xr-x 1 me me 4096 Jan 15 00:31 test.exe
-rwxr--r-- 1 me me  114 Jan 14 22:40 test.sh

Em seguida, a saída do script C #:

~/mono$ mono test.exe

/a/myfile/myfileseries.pdf
/a/myfile2/testfile.pdf

E a saída de depuração:

~/mono$ mono test.exe | rsync -avvvz --include='*/' --include-from=- --exclude='*' ./a/ ./b/
[client] add_rule(+ */)
[client] parse_filter_file(-,20,3)
[client] add_rule(+ /a/myfile/myfileseries.pdf)
[client] add_rule(+ /a/myfile2/testfile.pdf)
[client] add_rule(- *)
sending incremental file list
[sender] make_file(.,*,0)
[sender] hiding file 1Name.txt because of pattern *
[sender] showing directory myfile2 because of pattern */
[sender] make_file(myfile2,*,2)
[sender] hiding file 1.txt because of pattern *
[sender] hiding file 2.txt because of pattern *
[sender] hiding file Name1.txt because of pattern *
[sender] showing directory test1 because of pattern */
[sender] make_file(test1,*,2)
[sender] hiding file NaMe.txt because of pattern *
[sender] showing directory myfile because of pattern */
[sender] make_file(myfile,*,2)
send_file_list done
send_files starting
[sender] hiding file myfile/myfileseries.pdf because of pattern *
[sender] hiding file myfile2/testfile.pdf because of pattern *
[sender] hiding file test1/test.txt because of pattern *
    
por 15.01.2013 / 09:51
0

[EDITAR] Isso só funciona localmente. Para caminhos remotos, a estrutura de diretório deve ser criada primeiro.

Mais simples que a resposta aceita; Use --file-from, que inclui diretórios pai automaticamente e imprime o caminho do arquivo com% P

find /tmp/source -wholename '*[Nn][Aa][Mm][E]*' -printf '%P\n' | rsync -vzrm --exclude='*/' --files-from=- /tmp/source/ /tmp/target/

Você só precisa usar find e rsync .

    
por 11.11.2016 / 16:04