Estou tentando fazer benchmark para comparar duas maneiras diferentes de processar um arquivo. Eu tenho uma pequena quantidade de dados de entrada, mas para obter boas comparações, preciso repetir os testes várias vezes.
Em vez de apenas repetir os testes, eu gostaria de duplicar os dados de entrada várias vezes (por exemplo, 1000), para que um arquivo de 3 linhas se torne 3000 linhas e eu possa executar um teste muito mais satisfatório.
Estou passando os dados de entrada através de um nome de arquivo:
mycommand input-data.txt
perl
é tão eficiente que foi projetado para isso.Inicialmente, eu pensava que teria que gerar um arquivo secundário, mas poderia fazer o loop do arquivo original no Bash e usar algum redirecionamento para fazer com que ele apareça como um arquivo.
Provavelmente há uma dúzia de maneiras diferentes de fazer o loop, mas aqui estão quatro:
O terceiro método é improvisado a partir do comentário de maru abaixo e cria uma grande lista de nomes de arquivos de entrada para cat.
xargs
dividirá isso em tantos argumentos quanto o sistema permitir. É muito mais rápido que n gatos separados.A
awk
maneira (inspirada na resposta de Terdon ) é provavelmente a mais otimizada, mas duplica cada linha de cada vez. Isso pode ou não ser adequado a um aplicativo específico, mas é extremamente rápido e eficiente.Mas isso está gerando rapidamente. É provável que a saída do Bash seja muito mais lenta do que algo possa ler, portanto você deve gerar um novo arquivo para teste. Felizmente, essa é apenas uma extensão muito simples:
fonte
cat $(for i in {1..N}; do echo filename; done)
. Isso tem a limitação do tamanho do argumento, mas deve ser mais rápido.Aqui está uma
awk
solução:É essencialmente tão rápido quanto o Perl do @ Gnuc (corri as 1000 vezes e obtive o tempo médio):
fonte
awk '{for(i=0; i<1000; i++)print}' input-data.txt
que emita apenas 1000 cópias de cada linha por vez. Não serve para todas as ocasiões, mas ainda mais rápido, com menos atraso e não precisa reter o arquivo inteiro na RAM.123123123
estava bem, mas111222333
não estava. Sua versão é claramente mais rápida que a do Gnouc, e a média é de 0.00297 segundos. EDIT: risque isso, eu cometi um erro, é realmente equivalente a 0,004013 segundos.Eu usaria apenas um editor de texto.
Se você absolutamente precisar fazer isso pela linha de comando (isso requer que você tenha
vim
instalado, poisvi
não possui o:normal
comando), você pode usar:Aqui,
-es
(ou-e -s
) faz com que o vim opere silenciosamente, para que ele não assuma a janela do terminal e o-u NONE
impeça de olhar para o vimrc, o que deve torná-lo um pouco mais rápido do que o normal (talvez muito mais rápido, se você usar muitos plugins do vim).fonte
Aqui está uma linha única, sem scripts envolvidos:
Explicação
`yes input-data.txt | head -1000 | paste -s`
produz o textoinput-data.txt
1000 vezes separado por espaço em brancocat
como uma lista de arquivosfonte
xargs paste -s
? Isso funciona, mas não preserva novas linhas no arquivo de entrada.Enquanto trabalhava em um script completamente diferente, aprendi que, com 29 milhões de linhas de texto, o uso
seek()
e a operação de dados bytewise geralmente são mais rápidos do que linha por linha. A mesma idéia é aplicada no script abaixo: abrimos o arquivo e, em vez de repetir a abertura e o fechamento do arquivo (o que pode adicionar sobrecarga, mesmo que não seja significativo), mantemos o arquivo aberto e procuramos o início.O script em si é bastante simples de usar:
Para arquivos de texto de 3 linhas e 1000 iterações, tudo fica bem, cerca de 0,1 segundos:
O script em si não é muito elegante, provavelmente pode ser reduzido, mas faz o trabalho. Obviamente, adicionei alguns bits extras aqui e ali, como
error_out()
funções, o que não é necessário - é apenas um pequeno toque fácil de usar.fonte
Podemos resolver isso sem um arquivo adicional, nem programas especiais, o Bash puro (bem, o gato é um comando padrão).
Com base em um recurso do printf dentro do bash, podemos gerar uma sequência repetida):
Em seguida, podemos enviar essa lista de 1000 nomes de arquivos (repetidos) e chamar cat:
E, finalmente, podemos dar a saída ao comando para executar:
Ou, se o comando precisar receber a entrada no stdin:
Sim, o dobro <é necessário.
fonte
Eu geraria um novo arquivo usando o Unix for loop:
fonte