Compare awk com grep

Compare awk com grep

Eu executei abaixo 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 awkfoi muito mais rápido em me mostrar os resultados correspondentes. greptambé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, só quero saber a lógica por trás das pesquisas por awke grep.

Por que é awkmais rápido? Ambos os programas têm lógica de pesquisa diferente? E se eu confundir as strings na pesquisa acima, isso faz diferença na velocidade da pesquisa?

Responder1

O GNU greparmazena em buffer a saída, mas o GNU awknão. E mesmo se você não estivesse usando GNU awke estivesse usando alguma outra variante, provavelmente ainda seria armazenado em buffer de linha se você estivesse imprimindo em um terminal e, portanto, liberaria a saída para cada \newline que ocorresse, mas suas grepgravações em um canal seriam bloqueadas- buffer de qualquer maneira. Se você possui um GNU, greppode usá-lo grep --line-buffered ... | grep ...para comparação para ver os resultados o mais rápido possível. Provavelmente grepvencerá awkpraticamente qualquer teste de partida - especialmente um GNU grep.

Aqui está uma sedmaneira de fazer o que você quiser também:

sed -ne'/string4/{/string3/s/string[12]/&/p;}' <in >out

Responder2

O pipeline grep não pôde gerar nada até que o final greppara string4 correspondesse a algo e só recebe sua entrada depois que o buffer do pipe anterior é preenchido. Veja perguntas relacionadasQual é o tamanho do buffer do tubo?eDesative o buffer no pipe.

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 primeiro, para dar menos atenção ao regexp estendido.

Responder3

Seu exemplo do awk está fazendo toda a pesquisa regex de uma só vez. Para cada linha de entrada, se o primeiro, o segundo e o terceiro regex forem encontrados, a linha será impressa e você verá a saída essencialmente imediatamente (após o processamento da linha correspondente).

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

Se você tivesse um único arquivo de 1000 linhas e apenas a linha 5 correspondesse a todos os três regex, o comando awk forneceria a saída após o processamento da 5ª linha, antes de processar a 6ª linha. Compare isso com as instruções grep canalizadas. A 1ª invocação do grep encontraria a 5ª linha e quaisquer outras linhas que possam corresponder à 1ª regex, e após processar a 1000ª linha (final) de entrada, sua saída se tornará a entrada para a 2ª invocação do grep. A segunda invocação do grep processa quantas linhas a primeira saída e gera as linhas que correspondem ao primeiro e ao segundo regex, que então se torna a entrada para a terceira invocação do grep. À medida que a terceira invocação do grep processa cada linha, ele produzirá 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 a qualquer regex, exceto a linha 5, que corresponde a todas as 5, então o primeiro grep processa 1000 linhas, o segundo grep processa 1 linha e o terceiro grep processa 1 linha: 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, então a construção do grep canalizado processará 1000 + 1000 linhas + 5 = 2005 linhas antes de encontrar a correspondência na 5ª linha e ter alguma saída (será continue a processar as 995 linhas restantes da saída do segundo grep, mas você não verá mais nenhuma saída porque nada mais corresponderá).

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

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

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

em vez disso, 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á resultados tão rapidamente quanto a instrução awk, mas você poderá ver uma diferença.

Responder4

Embora grep, awk e sed possam ser usados ​​para tarefas semelhantes, cada um tem seus pontos fortes e fracos.

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

Sed é excelente na substituição de texto.

Grep é melhor para selecionar linhas de dados de entrada, então eu esperava que fosse mais rápido que awk para esta tarefa. Talvez se você combinar os 3 comandos grep em um, você verá isso. No momento, o grep está em desvantagem, pois precisa iniciar 3 vezes e a segunda e a terceira precisam aguardar a entrada da primeira. O que pode explicar por que o resultado chega com atraso. Embora eu não tenha certeza disso.

informação relacionada