Copiando um grande número de arquivos de um diretório para outro no Linux

7

Eu tenho um diretório contendo cerca de 280.000 arquivos. Eu quero movê-los para outro diretório.

Se eu usar cp ou mv , obtenho uma lista de argumentos de erro por muito tempo '.

Se eu escrever um script como

for file in ls *; do
   cp {source} to {destination} 
done

então, por causa do comando ls , seu desempenho diminui.

Como posso fazer isso?

    
por tripleee 10.02.2010 / 15:10

9 respostas

15

Use o rsync :

$ rsync -a {source}/ {destination}/

por exemplo,

$ rsync -a /some/path/to/src/ /other/path/to/dest/

(observe o / s arrastando)

Nota: se for uma operação demorada e você quiser ver alguma indicação de progresso durante a cópia, você pode adicionar a opção -v (verbose), que lista todos os arquivos sendo copiados, ou considere usar a opção --progress , para mais saída de progresso sucinta.     
por 10.02.2010 / 15:14
7

Eu estou perdendo duas twings nas respostas aqui, então estou adicionando mais uma.

Embora isso me lembre de adicionar outra resposta standard ...

Existemdoisproblemasaqui:

Ihaveadirectorycontainingaround280,000files.

Amaioriadasferramentasnãoseadaptatãobemaessenúmerodearquivos.NãoapenasamaioriadasferramentasdoLinuxouferramentasdoWindows,masmuitosprogramas.Eissopodeincluirseusistemadearquivos.Asoluçãoalongoprazoseria"bem, não faça isso então". Se você tiver arquivos diferentes, mas eles em diretórios diferentes. Se não espera continuar encontrando problemas no futuro.

Dito isso, vamos ao seu problema real:

If I use cp or mv then I get an error 'argument list too long'

Isso é causado pela expansão de * pelo shell. O shell tem espaço limitado para o resultado e ele se esgota. Isso significa que qualquer comando com um * expandido pelo shell terá o mesmo problema. Você precisará expandir menos opções ao mesmo tempo ou usar um comando diferente.

Um comando alternativo usado com frequência quando você se depara com esse problema é find . Já existem várias respostas mostrando como usá-lo, então não vou repetir tudo isso. No entanto, vou salientar a diferença entre \; e + , pois isso pode fazer uma grande diferença de desempenho e se encaixar perfeitamente na explicação de expansão anterior.

find /path/to/search --name "*.txt" -exec command {} \;

Encontrará todos os arquivos em path / to / search / e executará um comando com ele, mas observe as aspas em torno do * . Isso alimenta o * para o comando. Se nós não o encapsulássemos ou escaparmos, o shell tentaria expandi-lo e obteríamos o mesmo erro.

Por fim, quero mencionar algo sobre {}. Esses colchetes são substituídos pelo conteúdo encontrado por find. Se você terminar o comando com um ponto-e-vírgula ; (um que você precisa escapar do shell, portanto, \; nos exemplos), os resultados serão passados um por um. Isso significa que você executará 280000 comandos mv. Um para cada arquivo. Isso pode ser lento.

Como alternativa, você pode terminar com + . Isso passará tantos argumentos quanto possível ao mesmo tempo. Se o bash puder manipular 2000 argumentos, então, find / path -name "* filetype" -exec some_move {} + chamará o comando some_move cerca de 140 vezes, cada vez com 2000 argumentos. Isso é mais eficiente (leia: mais rápido).

    
por 25.04.2016 / 09:22
1

Você não precisa do ls, você pode simplesmente usar

for file in *; do
    cp $file /your/dest
done

ou você pode fazer algo como:

echo * | xargs -i cp {} /your/dest
    
por 10.02.2010 / 15:20
0
#!/bin/bash
d=$(date +%Y%m%d%H%m%s)
cd /path
tar zcvf "/destination/bakup_${d}.tar.gz" mydirectory_for_transer
    
por 10.02.2010 / 15:25
0

Supondo que você queira mover os arquivos dentro do mesmo sistema de arquivos, basta renomear o diretório que contém seus lacs e terminar com ele.

    
por 15.06.2010 / 01:28
0

Eu gosto de rsync para isso ou:

find dir1 -type f -exec cp {} dir2 \;
    
por 11.02.2010 / 04:11
0

Como sobre quando se movimenta (em vez de copiar):

$ find {origin}/ -maxdepth 1 -name "*" -o -name ".*" -exec mv '{}'  {destination}/ ';'

Acho que isso será mantido mantendo a estrutura (subdiretórios) e arquivos ocultos ou dirs, além de nenhum espaço extra consumido como o rsync + rm. E se {origin} e {destination} estiverem na mesma partição, será mais rápido.

    
por 08.05.2012 / 04:41
0

Usando o tar:

(cd {origin}; tar cf - .)|(cd {destination}; tar xvf -)

Funciona para iniciar as coisas quando a origem é inicialmente muito grande para o rsync, mas os deltas não são.

    
por 04.11.2015 / 23:35
0

No meu caso, cp e rsync eram lentas demais para copiar cerca de 4 milhões de arquivos de um HDD para SSD, então aqui está como eu fiz (todos os meus arquivos eram arquivos .txt na mesma pasta , então ajuste seu find para se adequar a você):

cd /path/to/source/folder
find . -name '*.txt' -print >/tmp/test.manifest
tar -c -T /tmp/test.manifest | (cd /path/to/destination/folder; tar xfp -)

Eu tive que imprimir os nomes dos arquivos em um arquivo temporário porque eu acessei o erro Argument list too long . Usar tar melhorou significativamente minhas velocidades de transferência, embora eu possa supor que arquivos que são menos facilmente compactados podem não ter um bom desempenho.

    
por 16.11.2016 / 18:15