Use paralelo para dividir muitos diretórios em subdiretórios ou paralelizar esta tarefa

1

Eu quero paralelizar a divisão de muitos diretórios em subdiretórios usando parallel ou usando outra ferramenta ou método.

Por exemplo Eu tenho 1 000 000 diretórios com conteúdo, mas é demais para um diretório, então eu quero criar 10 dirs no diretório principal e mover em cada um deles 100 000 dirs originais. Eu também quero usar a classificação por data. Eu já perguntei questão semelhante aqui , mas isso não é duplicar, porque tentei novos comandos, obtive novos resultados e agora reformulei a questão.

Então, eu já tentei isso

ls -tr|parallel -n100000 mkdir "dir_{#}"\;mv {} "dir_{#}" 

e isso

ls -tr | parallel -j10 -n100000 --no-notice -k 'mkdir -p dir_{#}; mv {} -t dir_{#}' 

comandos, mas ele move apenas ~ 10.000 em um subdir (às vezes ~ 6200, às vezes ~ 12.500) e cria subdiretórios em excesso - às vezes em 10 vezes mais do que eu preciso.

Eu também tentei usar isso:

ls -dtr * | parallel -j10 -n100000 --no-notice -k 'mkdir -p dir_{#}; mv {} -t dir_{#}'

mas deu bash: /bin/ls: Argument list too long .

É claro que não preciso exatamente de 100 000 dirs em cada subdiretório, pode ser de 101 000 ou 98 500 dirs, deve ser um número na faixa de 100 000

Como posso executar esta tarefa em paralelo ou usando parallel ?

    
por don-prog 25.11.2017 / 04:00

2 respostas

2

Este problema lida com IO pesado. Eu duvido que parallel seja realmente útil nessa situação.

De qualquer forma, sugiro que você considere uma abordagem "tradicional":

 mkdir dir_{1..10}
 ls -tr | nl | \
    awk '$2 !~ /^dir_/ {i=1+int($1/100000); print $2 | "xargs mv -t dir_"i}'

onde

  • ls -tr | nl ordena os diretórios por data e adiciona um número dir. auxiliar
  • $2 !~ /^dir_/ é usado para pular as pastas recém-criadas.
  • i=1+int($1/100000) calcula o número da pasta com base no número dir
  • print $2 | "xargs mv -t dir_"i se move sem proliferação de processo

Se possível compare também os respectivos tempos: time .... (e compartilhe os resultados conosco)

    
por 25.11.2017 / 12:47
3

O problema é que existe um limite superior de bytes que uma linha de comando pode tomar após a expansão do shell, esse limite depende do limite do sistema

getconf ARG_MAX

fazendo com que o número de argumentos por mv {} varie dependendo da duração do nome do arquivo de entrada sempre que você atingir o limite máximo.

Uma solução para evitar esse limite sem deixar de usar o paralelo é dividir a tarefa em dois estágios

ls -tr | parallel -N 100000 --pipe -k "mkdir dir_{#}; parallel -X mv -t dir_{#}"

Explicação

  • O primeiro estágio usa a opção --pipe para dividir o stdin em um número determinado de stdins menores , cada um contendo n linhas conforme especificado pela opção -N . Você pode observar o efeito usando este exemplo

    seq 1000000 | parallel -N 100000 --pipe wc -l
    

    que dá uma divisão exata na marca de 100.000

    100000
    100000
    100000
    ...
    
  • No segundo estágio, os paralelos internos recebem os stdins menores como seu novo stdin para executar suas tarefas, a opção -X insere tantos argumentos quanto o comprimento da linha de comando permitir

    mkdir dir_{#}; parallel -X mv -t dir_{#}
    
por 25.11.2017 / 10:52