Copie um tipo de arquivo específico, mantendo a estrutura da pasta

108

Eu tenho uma estrutura de pastas com um monte de arquivos * .csv espalhados pelas pastas. Agora eu quero copiar todos os arquivos * .csv para outro destino, mantendo a estrutura da pasta.

Funciona fazendo:

cp --parents *.csv /target
cp --parents */*.csv" /target
cp --parents */*/*.csv /target
cp --parents */*/*/*.csv /target
...

e assim por diante, mas eu gostaria de fazer isso usando um comando.

Wilfred Hughes
fonte

Respostas:

126

Existe alguma razão pela qual as pessoas resistem ao uso de achados -exec? É muito útil.

find . -name '*.csv' -exec cp --parents \{\} /target \;

Conheça suas ferramentas. ;-)

msb
fonte
62
Provavelmente por causa disso \ {\} \;
igo
12
'{}'funciona da mesma maneira #
1833 OrangeDog
3
Mesmo que -execdirseja mais seguro do que isso -exec, simplesmente substituir um pelo outro não preserva a estrutura da pasta conforme planejado.
Simon Shine
2
Por que recebo a mensagem 'Omitindo diretório' quando tento copiá-los com seu comando?
Vicky Dev
4
Você pode explicar por que os aparelhos devem ser escapados aqui?
Noumenon
46

Você também pode usar rsyncpara isso.

$ rsync -a --prune-empty-dirs --include '*/' --include '*.csv' --exclude '*' source/ target/

Se você deseja manter diretórios vazios da árvore de origem, pule a --prune-empty-dirsopção:

$ rsync -a --include '*/' --include '*.csv' --exclude '*' source/ target/

Se você não deseja links simbólicos, datas de modificação, permissões de arquivo, proprietários etc. preservados, substitua -apor outra combinação de -rlptgoD. ;-)

Dubu
fonte
11
-mé um atalho para --prune-emty-dirs.
Geremia
Além disso, a -Ropção pode ser adicionada para copiar a estrutura de diretórios pai da origem. (cf. minha resposta aqui.)
Geremia 24/09
-R funciona para mim! Obrigado
gigi2
32

Você pode usar o find e o cpio no modo de passagem

find . -name '*.csv' | cpio -pdm  /target

Ele encontrará todos os arquivos .csv no diretório atual e abaixo e os copiará para / target, mantendo a estrutura de diretórios enraizada ..

Se você usar

find /path/to/files -name '*.csv' | cpio -pdm /target

ele encontrará todo o arquivo em /path/to/filese abaixo e os copiará para /target/path/to/filese abaixo.


fonte
3
Eu tentei todas as respostas de cima para baixo até este, e este foi o único que funcionou na primeira tentativa
OscarRyz
21

O cpcomando permite vários argumentos de origem:

cp **/*.csv --parents ../target

CAVEAT: Estou usando um globo recursivo aqui; esta é a globstaropção no Bash 4+ e ksh, e é suportada por padrão em zsh. Globs recursivos não correspondem a arquivos e pastas ocultos, e algumas implementações seguem links simbólicos, enquanto outras não .

Se o seu shell não suportar globs recursivos, ou se você preferir não usá-los, faça o seguinte:

  • *.csv */*.csv */*/*.csv */*/*/*.csv - isto é obviamente muito redundante e requer saber quão profunda é a sua estrutura de diretórios.
  • $(find . -name '*.csv')- Isso vai coincidir com pastas e arquivos ocultos. findtambém suporta especificar se os links simbólicos são ou não seguidos, o que pode ser útil.
Kyle Strand
fonte
isto é exatamente o que eu tentei (o globo recursivo) e ele encontrou alguns, mas não todos? bem estranho. Eu tenho o mesmo resultado exato ao usar o npm CopyFiles script, mas se eu usar o comando find encontra tudo ...
Randyaa
@ Randya precisarei de mais alguns detalhes sobre quais arquivos, exatamente, não foram encontrados para ajudá-lo. Você pode encontrar a discussão aqui e continuar aqui sobre o comportamento preciso da glob recursiva útil.
Kyle Strand
11
Acontece que o globo recursivo não foi ativado por algum motivo ... Eu nunca me deparei com isso antes, mas eu o corrigi com apenas uma execução shopt -s globstarimediatamente antes do meu comando e está tudo bem. Obrigado pelo seguimento!
Randyaa
--parentsera o que eu estava procurando. obrigado
Josh
17

Este funcionou para mim:

find -name "*.csv" | xargs cp --parents -t /target

marko
fonte
Melhor resposta com a sintaxe mais simples. Funciona muito bem e é fácil de lembrar. Em muitos casos, find [things] | xargs [do stuff]é muito poderoso.
Everyday Astronaut
Acordado. Muito simples em comparação com algumas das outras respostas.
Tim B
11
Quebra se você tem espaços em nomes de arquivos
Michele Piccolini
@MichelePiccolini Os espaços nos nomes de arquivos podem ser tratados com find -print0e xargs -0.
pasztorpisti 19/09
8

Supondo que você deseja replicar essa estrutura de ./sourcepara ./destination:

cd source
find . -name "*.csv" | xargs tar cvf - | (cd ../destination ; tar xfp -)

Estou preparado para contar isso como uma linha, cd sourcesendo uma concha embutida.

Chapeleiro Louco
fonte
2
Eu não acho que ele realmente significa um comando - apenas não ter que fag sobre como o seu exemplo;)
tartem a -Copção de evitar a necessidade de alterar o diretório primeiro.
Bart
8

Da página de rsyncmanual:

-R, - relativo

Use caminhos relativos. Isso significa que os nomes de caminho completo especificados na linha de comando são enviados ao servidor, e não apenas as últimas partes dos nomes de arquivos. Isso é particularmente útil quando você deseja enviar vários diretórios diferentes ao mesmo tempo. Por exemplo, se você usou este comando:

rsync -av /foo/bar/baz.c remote:/tmp/

... isso criaria um arquivo chamado baz.c em / tmp / na máquina remota. Se você usou

rsync -avR /foo/bar/baz.c remote:/tmp/

então, um arquivo chamado /tmp/foo/bar/baz.c seria criado na máquina remota, preservando seu caminho completo. Esses elementos extras do caminho são chamados de "diretórios implícitos" (ou seja, os diretórios "foo" e "foo / bar" no exemplo acima).

Então, isso funcionaria também:

rsync -armR --include="*/" --include="*.csv" --exclude="*" /full/path/to/source/file(s) destination/
Geremia
fonte