Quando rsync
é executado, ele testa os nomes encontrados na origem em relação aos padrões e o primeiro padrão correspondente entra em vigor:
$ rsync -avv --exclude='*' --include='copyme' /tmp/src/ /tmp/tgt/
sending incremental file list
[sender] hiding directory A because of pattern *
[sender] hiding directory B because of pattern *
delta-transmission disabled for local transfer or --whole-file
total: matches=0 hash_hits=0 false_alarms=0 data=0
sent 51 bytes received 86 bytes 274.00 bytes/sec
total size is 0 speedup is 0.00
Quando um diretório foi excluído (veja "ocultando diretório ..." acima), seu conteúdo não é mais considerado. A reversão dos padrões de exclusão e inclusão não ajudará, pois nunca chegará aos diretórios copyme
.
O manual rsync
diz:
For instance, to include
/foo/bar/baz
, the directories/foo
and/foo/bar
must not be excluded. Excluding one of those parent directories prevents the examination of its content, cutting offrsync
's recursion into those paths and rendering the include for/foo/bar/baz
ineffectual (sincersync
can't match something it never sees in the cut-off section of the directory hierarchy).
Então, ao invés disso:
$ rsync -avv --include='[AB]' --include='copyme/***' --exclude='*' /tmp/src/ /tmp/tgt/
sending incremental file list
[sender] showing directory A because of pattern [AB]
[sender] showing directory B because of pattern [AB]
[sender] showing directory A/copyme because of pattern copyme/***
[sender] hiding file A/no.txt because of pattern *
[sender] showing file A/copyme/yes.txt because of pattern copyme/***
[sender] showing directory B/copyme because of pattern copyme/***
[sender] hiding file B/no.txt because of pattern *
[sender] showing file B/copyme/yes.txt because of pattern copyme/***
created directory /tmp/tgt
delta-transmission disabled for local transfer or --whole-file
./
A/
A/copyme/
A/copyme/yes.txt
B/
B/copyme/
B/copyme/yes.txt
total: matches=0 hash_hits=0 false_alarms=0 data=10
sent 305 bytes received 175 bytes 960.00 bytes/sec
total size is 10 speedup is 0.02
Note que a exclusão tem que vir por último, após as inclusões. O padrão copyme/***
corresponde ao nome do diretório copyme
e a qualquer nome de caminho abaixo dele.
Se você não quiser codificar os nomes dos diretórios A
e B
:
for dir in /tmp/src/*; do
[ ! -d "$dir" ] && continue
rsync -avv --include="${dir##*/}" --include='copyme/***' --exclude='*' /tmp/src/ /tmp/tgt/
done
Isso produziria
sending incremental file list
[sender] showing directory A because of pattern A
[sender] hiding directory B because of pattern *
[sender] showing directory A/copyme because of pattern copyme/***
[sender] hiding file A/no.txt because of pattern *
[sender] showing file A/copyme/yes.txt because of pattern copyme/***
created directory /tmp/tgt
delta-transmission disabled for local transfer or --whole-file
./
A/
A/copyme/
A/copyme/yes.txt
total: matches=0 hash_hits=0 false_alarms=0 data=5
sent 180 bytes received 148 bytes 656.00 bytes/sec
total size is 5 speedup is 0.02
sending incremental file list
[sender] hiding directory A because of pattern *
[sender] showing directory B because of pattern B
[sender] showing directory B/copyme because of pattern copyme/***
[sender] hiding file B/no.txt because of pattern *
[sender] showing file B/copyme/yes.txt because of pattern copyme/***
delta-transmission disabled for local transfer or --whole-file
B/
B/copyme/
B/copyme/yes.txt
total: matches=0 hash_hits=0 false_alarms=0 data=5
sent 180 bytes received 117 bytes 594.00 bytes/sec
total size is 5 speedup is 0.02
O resultado seria
$ tree src tgt
src
|-- A
| |-- copyme
| | '-- yes.txt
| '-- no.txt
'-- B
|-- copyme
| '-- yes.txt
'-- no.txt
4 directories, 4 files
tgt
|-- A
| '-- copyme
| '-- yes.txt
'-- B
'-- copyme
'-- yes.txt
4 directories, 2 files
Outra abordagem que não usa padrões de exclusão ou inclusão com rsync
, mas usa find
para localizar os diretórios copyme
e, em seguida, rsync
para copiá-los:
find /tmp/src -type d -name 'copyme' -prune -exec sh -c '
cd /tmp/src && rsync -aRvv "${1#/tmp/src/}/" /tmp/tgt/' sh {} ';'
Observe o sinalizador -R
( --relative
) usado com rsync
aqui.
O script sh -c
executado para cada diretório copyme
encontrado faz um cd
para /tmp/src
e copia o nome do caminho com o bit /tmp/src
inicial de seu caminho removido.
O -prune
no comando find
para find
de procurar por mais diretórios copyme
dentro do diretório encontrado.