Como posso copiar recursivamente arquivos por extensão, preservando a estrutura de diretórios?

71

Na linha de comando do Linux, eu gostaria de copiar um conjunto (muito grande) de .txtarquivos de um diretório (e seus subdiretórios) para outro.

Preciso que a estrutura de diretórios permaneça intacta e ignore os arquivos, exceto os que terminam em .txt.

bagagem não reclamada
fonte
2
Tendo cp e find como tags na sua pergunta, isso significa que você está vinculado a essas opções? Como o seu conjunto de dados é muito grande, faz sentido supor que o processo de cópia possa ser interrompido por alguns motivos e você precisará reiniciá-lo. Não sei se a abordagem find / cp poderá retomar a transferência e copiar apenas a parte que está faltando. Se você não está vinculado a encontrar / cp, pode considerar o rsync, que é mais inteligente. Sua opção --exclude permitirá que você pule arquivos .txt.
vtest
Fair call - rsync provavelmente é a melhor opção. Não está vinculado a encontrar / cp. (Eu usei-los de qualquer maneira - rsync não foi instalado na máquina remota, foi um servidor web ao vivo e eu queria deixar tão pequena de uma pegada possível)
unclaimedbaggage

Respostas:

96

Você pode usar o find e o cpio para fazer isso

cd /top/level/to/copy
find . -name '*.txt' | cpio -pdm /path/to/destdir

(-updm for overwrite destination content.)
cedric
fonte
por que eu? Eu pensei que é apenas para manter o arquivo modificar data.
Mubashar
7
cd /source/path
find -type f -name \*.txt -exec install -D {} /dest/path/{} \;
sborsky
fonte
Você está perdendo um tempo .depois find. Também no macOS 10.13.1, isso funcionou:find . -type f -name "*.txt" -exec install -v {} /dest/path/{} \;
grim
2

Outra abordagem

find . -name '*.txt' -exec rsync -R {} path/to/dext \;

Marc
fonte
Eu gosto desta solução. Eu costumava find . -iname '*.txt' -exec rsync -Rptgon {} path/to/dext \;fazer uma correspondência sem distinção entre maiúsculas e minúsculas e preservar a propriedade e as permissões.
MountainX
1

A maneira mais fácil que funcionou para mim:

cp --parents -R jobs/**/*.xml ./backup/

Um problema é que você precisa navegar para o diretório "desejado" antes para que o "caminho pai" esteja correto.

Verifique também se você ativou globs recursivos no bash:

shopt -s globstar
icyerasor
fonte
1

Que tal você primeiro copiá-lo com

cp -r /old/folder /new/folder

então vá para a nova pasta e execute

find . -type f ! -iname "*.txt" -delete

ou apenas

cp -r /old/folder /new/folder && find . -type f ! -iname "*.txt" -delete

Edit: ok, você quer um comando que filtre (eu não testei isso porque meu sistema não possui o cpiocomando!). Aqui é onde eu o encontrei: http://www.gnu.org/software/findutils/manual/html_mono/find.html#Copying-A-Subset-of-Files

find . -name "*.txt" -print0 |
     cpio -pmd0 /dest-dir

Por favor testar este primeiro, porque eu não tentei ainda. Se alguém verificar, isso seria ótimo.

Dennis
fonte
acena Felicidades - isso iria funcionar, mas sem filtragem para .txt eu estou olhando para alguns milhões de arquivos (que sai em algumas centenas de GB). Se necessário, talvez seja necessário, mas eu adoraria filtrar enquanto copia, se possível
unclaimedbaggage
11
Saúde, a versão editada funciona se eu remover o '0' de -pmd0
unclaimedbaggage
Você deve manter o 0in -pmd0e adicionar -print0ao final do findcomando (imediatamente antes do |).
G-Man
1

Eu estava tentando fazer a mesma coisa no macOS, mas nenhuma das opções realmente funcionou para mim. Até eu descobrir ditto.

Eu tive que copiar muitos arquivos .wav e pular arquivos de vídeo ... Então, aqui está o que eu vim com:

find . -type f -iname "*.wav" -ls -exec ditto {} /destination/folder/{} \;

  • find .- Executa a busca na pasta atual. certifique-se de cd /source/folderantes de começar

  • -type f - Especifica procurar apenas arquivos

  • -iname "*.wav" - Isso diz para procurar maiúsculas e minúsculas * .wav
  • -ls- Isso mostra o arquivo em que ele está trabalhando. Caso contrário, não mostra nada.
  • -exec ditto {} /destination/folder/{} \; - Faz todo o trabalho de copiar e criar os arquivos com a mesma árvore de diretórios.
Benjamin McGuire
fonte
0

Navegue para o diretório:

find . -regex '<regexp_to_get_directories_and_files_you_want>' | xargs -i cp -r --parents {} path/to/destination

É um pouco mais direto e poderoso, se você gerenciar expressões regulares.

keywalker
fonte
-1

Navegue para o diretório:

cp '*.css' /path/to/destination

Você precisará navegar para cada pasta do diretório, mas isso é melhor do que a maioria das opções que eu vi até agora.

Fénix
fonte
Este método não é recursiva, o que significa que para grandes diretórios que você poderia estar fazendo isso por um bom tempo ...
Iain Reid