Maneira eficiente de criar vários arquivos

7

Eu tenho testado o diretório find que está usando max inodes e durante o teste eu executei

touch test_{1..1391803}.txt

Mas isso me dá um erro "-bash: /usr/bin/touch: Argument list too long" , agora estou executando o comando abaixo, mas parece que vai demorar o tempo de Hugh

ruby -e '1.upto(1391803) { |n| %x( touch "test_#{n}.txt" ) }'

Então a pergunta é: existe alguma maneira de criar vários arquivos em um pequeno período de tempo? devo tocar 1 lac arquivos por loop ou de qualquer maneira melhor?

Resultado do teste:

Não. 1

[root@dc1 inode_test]# time seq 343409 | xargs touch

real    0m7.760s
user    0m0.525s
sys     0m4.385s

Não. 2

[root@test-server inode_test]# time echo 'for (i=1;i<=343409;i++) i' | bc | xargs touch

real    0m8.781s
user    0m0.722s
sys     0m4.997s

Não. 3

[root@test-server inode_test]# time printf '%s ' {1..343409} | xargs touch

real    0m8.913s
user    0m1.144s
sys     0m4.541s

Não. 4

[root@test-server inode_test]# time awk 'BEGIN {for (i=1; i<=343409; i++) {printf "" >> i; close(i)}}'

real    0m12.185s
user    0m2.005s
sys     0m6.057s

Não. 5

[root@test-server inode_test]# time ruby -e '1.upto(343409) { |n| File.open("#{n}", "w") {} }'

real    0m12.650s
user    0m3.017s
sys     0m4.878s
    
por Rahul Patil 19.03.2014 / 09:14

3 respostas

12

A limitação está no tamanho dos argumentos em execução de um comando. Portanto, as opções são executar um comando com menos argumentos, por exemplo, com xargs para executar lotes menores, aumentar o limite ( ulimit -s 100000 no Linux), não executar nada (fazer tudo no shell) ou criar a lista na ferramenta que cria os arquivos.

zsh , ksh93 , bash :

printf '%s ' {1..1391803} | xargs touch

printf está incorporado, por isso não há exec , por isso o limite não é atingido. xargs divide a lista de argumentos passados para touch para evitar quebrar o limite. Isso ainda não é muito eficiente, pois o shell precisa primeiro criar toda a lista (lenta especialmente com bash ), armazená-la na memória e depois imprimi-la.

seq 1391803 | xargs touch

(supondo que você tenha um comando seq ) seria mais eficiente.

for ((i=1; i<=1391803; i++)); do : >> "$i"; done

Tudo é feito no shell, sem lista grande armazenada na memória. Deve ser relativamente eficiente, exceto talvez com bash .

POSIXly:

i=1; while [ "$i" -le 1391803 ]; do : >> "$i"; i=$(($i + 1)); done

echo 'for (i=1;i<=1391803;i++) i' | bc | xargs touch

awk 'BEGIN {for (i=1; i<=1391803; i++) {printf "" >> i; close(i)}}'
    
por 19.03.2014 / 09:36
3

Você está sendo limitado pelo número máximo de argumentos que o touch pode manipular. A melhor aposta seria usar um loop. Você não precisa do ruby para fazer isso, no entanto:

for i in $(seq 1391803); do touch test_${i}.txt; done

Uma abordagem alternativa pode ser dividir o número em blocos, digamos 100, e depois alimentar esses números em touch de cada vez:

i=1; while ((i<=1391803)); do touch $(seq $i $((i+99))); i=$((i+100)); done
    
por 19.03.2014 / 09:24
3

No seu exemplo, o Bash reclama porque, ao expandir test_{1..1391803}.txt , ele acaba com uma linha de comando de argumento muito longa. O comprimento máximo da linha de comando que pode ser passado para um comando é fixado pelo kernel, porque a chamada de sistema exec , que é responsável por iniciar novos processos (na verdade, substituindo o programa de um processo existente por outro) deve colocar esses argumentos na pilha do processo e o tamanho da pilha são limitados.

Acho que a maneira mais eficiente de fazer isso é não iniciar um novo processo touch sempre que você quiser um arquivo.

Você poderia em ruby, por exemplo:

ruby -e '1.upto(1391803) { |n| File.open("test_#{n}.txt", "w") {} }'

Dessa forma, você inicia apenas um processo que criará todos os arquivos sem a necessidade de iniciar o programa touch .

Este comando inicia o intérprete de ruby. Em seguida, ruby cria um loop no intervalo 1..1391803 e, para cada número, chama a função File.open , que executa a chamada de sistema open com um nome de arquivo construído com o número. Como o bloco após File.open está vazio, o arquivo é imediatamente fechado.

    
por 19.03.2014 / 09:28