Comparar awk vs. grep

3

Eu corri abaixo de dois comandos para arquivos muito grandes

grep -E 'string1|string2' 151103*.log|grep 'string3' | grep string4

awk '/string1|string2/ && /string3/ && /string4/' 151103*.log

Demorou quase o mesmo tempo para execução. Mas awk foi muito mais rápido para me mostrar os resultados correspondentes. grep também me mostrou o mesmo resultado, mas no final, quando o processo foi concluído.

Ambos levaram o mesmo tempo para o processo ser concluído, apenas querem saber a lógica por trás das pesquisas por awk e grep .

Por que awk é mais rápido? Ambos os programas possuem lógica de pesquisa diferente? E se eu misturar as strings na pesquisa acima, isso faz diferença na velocidade de busca?

    
por Chittha Shetty 04.11.2015 / 16:38

4 respostas

6

GNU grep buffers de saída, mas GNU awk não. E mesmo se você não estivesse usando o GNU awk e estivesse usando alguma outra variante, provavelmente ainda estaria com buffer de linha se estivesse imprimindo em um terminal e então liberaria a saída para cada \n ewline, mas seu grep escreve em um pipe e assim bloquearia o buffer de qualquer maneira. Se você tiver um grep do GNU, poderá usar grep --line-buffered ... | grep ... para sua comparação para ver os resultados mais rapidamente. É provável que grep derrote awk em praticamente todos os testes de partida - especialmente um GNU grep .

Aqui está um sed para fazer o que você quer também:

sed -ne'/string4/{/string3/s/string[12]/&/p;}' <in >out
    
por 04.11.2015 / 16:55
3

O pipeline do grep não pôde produzir nada até que o% finalgrep para string4 correspondesse a algo, e só recebesse sua entrada depois que o buffer do canal anterior fosse preenchido. Veja perguntas relacionadas Qual é o tamanho do buffer de tubos? e Desativar o buffer no tubo .

Dependendo da frequência das strings em sua entrada, você poderá ver uma diferença nos tempos de execução, colocando as pesquisas estáticas em primeiro lugar, para dar menos tempo para o regexp estendido.

    
por 04.11.2015 / 16:56
3

Seu exemplo de awk é fazer toda a pesquisa regex em uma única passagem. Para cada linha de entrada, se a primeira, segunda e terceira regex forem encontradas, a linha será impressa e você verá a saída essencialmente imediatamente (após o processamento da linha correspondente).

Seu exemplo grep está usando 3 invocações diferentes de grep (uma para cada regex) para fazer a mesma coisa, mas a saída de cada chamada se torna a entrada para a próxima, o que significa que cada uma precisa ser concluída antes da próxima. para processar.

Se você tivesse um único arquivo de 1000 linhas e apenas a linha 5 correspondesse a todas as três expressões regulares, o comando awk lhe daria saída após o processamento da 5ª linha, antes de processar a 6ª linha. Compare isso com as instruções piped grep. A primeira invocação do grep iria encontrar a 5ª linha e quaisquer outras linhas que pudessem corresponder ao 1º regex, e depois de processar a 1000ª (final) linha de entrada, sua saída se tornaria a entrada para a 2ª invocação do grep. A segunda invocação do grep processa, no entanto, muitas linhas - a primeira saída e as linhas que correspondem à primeira e segunda regex, que então se torna a entrada para a terceira chamada do grep. Como a 3ª invocação do grep processa cada linha, irá gerar qualquer linha que corresponda ao seu regex.

Você pode comparar os melhores e piores casos de grep para o exemplo acima: se nenhuma das linhas corresponder à regex, exceto a linha 5, que corresponde a todas as 5, então o primeiro grep processa 1000 linhas, o segundo grep processa 1 line, e o terceiro grep processa 1 linha: ele processará 1002 linhas antes de ter qualquer saída (melhor caso). Se todas as linhas corresponderem aos dois primeiros regex, mas apenas uma linha corresponder ao terceiro regex, a construção do grep canalizado processará linhas 1000 + 1000 linhas + 5 = 2005 antes de encontrar a correspondência na quinta linha e ter alguma saída (será continue processando as 995 linhas restantes da saída do segundo grep, mas você não verá mais nenhuma saída porque nada mais irá corresponder).

Compare isso com o comando awk, que verifica todos os três regex simultaneamente para cada linha e fornece a saída após o processamento da quinta linha. A diferença será exagerada quando você verificar mais arquivos simultaneamente.

Por exemplo, compare se você visualizar a saída mais rapidamente se, em vez de executar o comando grep em todos os arquivos simultaneamente, como você fez acima (teoricamente, você deve, mas os resultados podem variar dependendo da distribuição de ocorrências):

grep -E 'string1|string2' 151103*.log|grep 'string3' | grep string4

você executa a série de comandos grep em cada arquivo individualmente, assim:

for i in 151103*.log; 
  do grep -E 'string1|string2' $i |grep 'string3' | grep string4; 
done

Isso ainda não produzirá a saída tão rapidamente quanto a instrução awk, mas você poderá ver a diferença.

    
por 04.11.2015 / 22:48
2

Enquanto grep e awk e sed podem ser usados para tarefas similares, cada um tem seus pontos strongs e fracos.

O awk funciona melhor para dados tabularizados ou quando você precisa realizar cálculos, etc.

Sed é excelente na substituição de texto.

O grep é melhor para selecionar linhas dos dados de entrada, então eu esperava que fosse mais rápido que o awk para essa tarefa. Talvez se você combinar os 3 comandos do grep em um que seja o que você verá. Neste momento, o grep está em desvantagem, uma vez que precisa de iniciar 3 vezes e o segundo e terceiro precisam de esperar pela entrada do primeiro. O que pode explicar porque o resultado vem com um atraso. Embora eu não tenha certeza disso.

    
por 04.11.2015 / 16:50

Tags