Linux: Copie todos os arquivos correspondentes ao padrão de dir e subdirta em um único dir

31

Se eu quisesse copiar todos os *.soarquivos de srcpara dsteu faria:

cp src/*.so dst

No entanto, quero copiar todos os *.soarquivos do src e subdividi-los em dst. Alguma pista?

Albus Dumbledore
fonte

Respostas:

36

Experimentar:

find src/ -type f | grep -i so$ | xargs -i cp {} dst
Mike Insch
fonte
17
findpode fazer a correspondência de padrões e executar comandos. Não há necessidade de canalizar sua saída:find src/ -type f -name '*.so' -exec cp '{}' dst/ ';'
jáquer 19/07/11
1
Sim, pode, no entanto, muitas vezes é mais fácil ler um pipeline, também os recursos de correspondência de greppadrões superam em muito os padrões de shell simples usados ​​no -nameparâmetro para find. xargsé também muito mais poderoso do que o -execparâmetro para find.
181111 Mike Insch
2
A solução do @jaquer é muito melhor porque no MacOSX o utilitário xargs não possui a opção -i. Mas sua solução funciona como um encanto.
bialix
Eu estava lutando com uma mensagem de erro no argumento -i para xargs até ler o comentário do @bialix sobre a solução do jaquer, que funcionou perfeitamente no meu Mac. Graças
svannoy
Isso criará subdiretórios, conforme necessário?
Lennart Rolland
15

Se você estiver usando o Bash, poderá ativar a globstar opção shell para corresponder arquivos e diretórios recursivamente:

shopt -s globstar
cp src/**/*.so dst

Se você precisar encontrar arquivos cujos nomes começam com .e / ou arquivos nos diretórios cujos nomes começam com ., defina dotglobtambém a opção (por exemplo, com shopt -s dotglob). Você pode definir os dois em um comando:

shopt -s globstar dotglob
jáquer
fonte
Doesn't copy files in subdirectories starting with a . in their name
rboy
8

Eu tentei o comando sugerido por Mike:

find src/ -type f | grep -i so$ | xargs -i cp {} dst

mas acabou despejando todos os arquivos no diretório dstcom seus caminhos relativos perdidos.

Para manter os caminhos relativos, o comando precisa ser modificado para isso:

find src/ -type f | grep -i so$ | xargs -i cp {} dst/{}
Ilya Druker
fonte
7
+1. No entanto, isso pressupõe que os diretórios correspondentes aos caminhos de origem relativos existam em dst. Caso não seja assim, use cp --parents. Além disso, não se esqueça de citar os nomes dos arquivos. Assim: ... | xargs -i cp --parents "{}" dst(observe que o último argumento para cpagora é "apenas" o diretório de destino). O comando pode ser feita ainda mais curto (e provavelmente mais rápido) usando a -tbandeira: ... | xargs cp --parents -t dst.
precisa saber é o seguinte
1
@ Stephan202 eu tive que usar #... | xargs cp {} --parents -t dst.
warvariuc 11/11/2015
para aqueles em um mac, --parentsnão está disponível. Eu usei dittoem seu lugar: stackoverflow.com/questions/11246070/cp-parents-option-on-mac
Bryan Young
3

Outra maneira de fazer isso é assim:

find src/ -type f -name "*.so" -exec cp {} dst/ \;
Kyriakos
fonte
E isso deve reduzir o número de cpprocessos: ... -exec cp -t dst/ {} +.
Kamil Maciorowski
Hey Kamil! Obrigado pelo comentário! Você pode me explicar como sua solução torna as coisas mais rápidas! Sempre disposto a aprender mais :)
Kyriakos
Quando você termina -execcom ;, {}é substituído por um caminho por vez. Você recebe um separado cppara cada arquivo. A +sintaxe findsubstitui {}por vários resultados (até um limite definido pelo sistema de comprimento da linha de comando; restrição: {}deve ser a última coisa antes +, portanto cp -t). Criar e encerrar um processo é algo relativamente caro. Por esse motivo, é bom usar +sempre que você espera muitos resultados. Nesse caso, a cópia de muitos arquivos pode levar muito tempo, portanto a diferença pode passar despercebida; no entanto, é uma boa prática.
Kamil Maciorowski
1

O grep pode ser substituída por utilizar do achado -name :

find src/ -type f -name "*.so" | xargs -i cp {} dst/{}
º. Thielemann
fonte