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 de diretórios com conteúdo, mas é demais para um diretório, então quero criar 10 diretórios no diretório principal e mover em cada um deles 100.000 diretórios originais. Também quero usar a classificação por data. eu já pergunteipergunta semelhante aqui, mas não é duplicado, pois 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 isto
ls -tr | parallel -j10 -n100000 --no-notice -k 'mkdir -p dir_{#}; mv {} -t dir_{#}'
comandos, mas ele move apenas ~ 10.000 para um subdiretório (às vezes ~ 6.200, às vezes ~ 12.500) e cria muitos subdiretórios - às vezes 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 deubash: /bin/ls: Argument list too long
.
Claro, não preciso exatamente de 100.000 dirs em cada subdiretório, pode ser 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
?
Responder1
O problema é que existe um limite superior de bytes que uma linha de comando pode ocupar após a expansão do shell, esse limite depende do limite do sistema
getconf ARG_MAX
causando assim o número de argumentos pormv {}
varie dependendo do comprimento do nome do arquivo de entrada sempre que você atingir o limite máximo.
Uma solução para evitar esse limite sem abrir mão do uso do paralelo é dividir a tarefa em duas etapas
ls -tr | parallel -N 100000 --pipe -k "mkdir dir_{#}; parallel -X mv -t dir_{#}"
Explicação
A primeira etapa usa a opção
--pipe
de dividir o stdin em um determinado número destdins menores, cada um contendo n linhas conforme especificado pela opção-N
. Você pode observar o efeito usando este exemploseq 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 tomam ostdins menorescomo seu novo stdin para executar seus trabalhos, a
-X
opção insere tantos argumentos quanto o comprimento da linha de comando permitirmkdir dir_{#}; parallel -X mv -t dir_{#}
Responder2
Este problema lida com IO pesado. Duvido que parallel
seja realmente útil nesta 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
classifica os diretórios por data e adiciona um número de diretório 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 do diretórioprint $2 | "xargs mv -t dir_"i
move-se sem proliferação de processos
Se possível compare também os respectivos tempos: time ....
(e partilhe connosco os resultados ☺)