$ tree
.
'-- MainDir
|-- dir1
| |-- notes.txt
| |-- some_file-1
| |-- some_file-2
| '-- some_file-3
'-- dir17
|-- README.txt
|-- some_file-1
|-- some_file-2
'-- some_file-3
3 directories, 8 files
Usando rsync
:
$ rsync -a --include '*.txt' --exclude '*/*' MainDir/ MainDir/txtFiles/
$ tree
.
'-- MainDir
|-- dir1
| |-- notes.txt
| |-- some_file-1
| |-- some_file-2
| '-- some_file-3
|-- dir17
| |-- README.txt
| |-- some_file-1
| |-- some_file-2
| '-- some_file-3
'-- txtFiles
|-- dir1
| '-- notes.txt
'-- dir17
'-- README.txt
6 directories, 10 files
O comando usa --include '*.txt'
para incluir todos os arquivos com .txt
nome do arquivo e --exclude '*/*'
para excluir outros arquivos. Usando -a
ou --archive
, uma cópia da parte da hierarquia de origem que é copiada é criada no destino.
Executar isso novamente resultaria em um diretório MainDir/txtFiles/txtFiles
vazio sendo criado. Adicionar -m
ou --prune-empty-dirs
à invocação de rsync
evitaria isso.
Usando find
(de MainDir
):
$ find . -type f -name '*.txt' ! -path '*/txtFiles/*' \
-exec sh -c 'for n; do
d="txtFiles/${n%/*}";
mkdir -p "$d" && cp "$n" "$d"
done' sh {} +
Isso localiza todos os arquivos regulares cujos nomes correspondem a *.txt
e que não estão em um diretório txtFiles
.
Para cada caminho de nome de arquivo encontrado, a parte do diretório do caminho é criada em txtFiles
e o arquivo é copiado lá.
A única diferença entre a abordagem rsync
e isso é que rsync
pode copiar arquivos não regulares que correspondem ao nome dado (diretórios chamados pipes etc.) e que o comando find
deve ser executado de dentro de MainDir
.