Shell Script - Awk Optimization

3

Eu estou procurando por alguma ajuda na tentativa de otimizar um script de análise de log de rede bro, aqui está o plano de fundo:

Eu tenho uma grande quantidade de logs bro, mas estou interessado apenas em consultar IPs dentro do meu escopo (várias sub-redes de tamanho variável).

Portanto, eu tenho um arquivo de texto com padrões de regex para corresponder aos intervalos de IP que estou procurando: scope.txt:

/^10\.0\.0\.([8-9]|[1-3][0-9]|4[0-5])$/

(scope.txt contém até mais 20 linhas de outros intervalos de IP em padrões de regex) findInScope.sh:

#!bin/sh
for file in /data/bro_logs/2016-11-26/conn.*.log.gz
do
    echo "$file"
    touch /tmp/$file
    for nets in $(cat scope.txt)
    do
        echo "$nets"
        zcat $file | bro-cut -d | awk '$3 ~ '$nets' || $5 ~ '$nets'' >> /tmp/$file
    done
    sort /tmp/$file | uniq > ~/$file
    rm /tmp/$file
done

Quanto mais plano de fundo, cada hora de logs de conexão do bro original é de aproximadamente 100 MBs, meu script atual leva cerca de 10 a 20 minutos para analisar uma hora de dados de log. Um dia de registros pode levar até 3 horas.

Eu pensei em uma única instrução awk com 40 ou mas decidi que não quero fazer isso porque quero um arquivo scope.txt separado para usar o mesmo script para diferentes escopos de intervalos de IP.

Eu também tentei o zcat em vários arquivos conn.log (ou seja, zcat conn. *. log.gz), mas o arquivo de saída acabou sendo mais de 1 GB, e eu queria manter os registros de hora em hora intactos.

    
por IvDogg 27.11.2016 / 10:15

2 respostas

6

Você deve ganhar muito passando o arquivo de log apenas uma vez pelo awk. Isso significa combinar todos os regexps em um. Se você não quiser fazer isso no seu arquivo scope.txt , faça antes de chamar o awk. Por exemplo,

sed <scope.txt 's|^/\^|(|; s|\$/$|)|; $!s/$/|/' | tr -d '\n' >pattern

zcat $file | bro-cut -d |
awk '
BEGIN{ getline pat <"pattern"; pat = "^(" pat ")$" }
$3 ~ pat || $5 ~ pat
'  >~/$file

O sed substitui o /^ e $ em torno de cada linha regexp por um par de () , adiciona um | no final da linha e coloca o resultado em uma única linha no arquivo pattern . Este arquivo é, portanto, todos os padrões ou juntos. O ^(...)$ ausente é adicionado na instrução BEGIN do script awk, que lê o arquivo padrão na variável pat .

O texto acima substitui o seu loop for interno e o sort|uniq .

    
por 27.11.2016 / 11:17
2

A resposta mais simples é usar scope.txt , muito ligeiramente modificado, como patternfile, e usar zcat | grep (ou apenas zgrep ) para obter as linhas necessárias.

Primeiro, modifique o arquivo scope para alterar:

/^10\.0\.0\.([8-9]|[1-3][0-9]|4[0-5])$/

para:

(^|[^0-9.])(10\.0\.0\.([8-9]|[1-3][0-9]|4[0-5]))($|[^0-9.])

Para fazer isso facilmente, você pode usar:

sed -e 's:^/\^:(^|[^0-9.])(:' -e 's:\$/$:)($|[^0-9.]):' scope.txt > grepscope.txt

Em seguida, faça sua pesquisa:

zgrep -Ehf grepscope.txt /data/bro_logs/2016-11-26/conn.*.log.gz | less

Ou, desde que você queira a saída de cada arquivo armazenado separadamente:

for f in /data/bro_logs/2016-11-26/conn.*.log.gz; do
    zgrep -Ehf grepscope.txt "$f" | sort -u > ~/"${f##*/}"
done

Note também que a variável de loop "for" $f conterá o caminho inteiro para cada arquivo por vez; para evitar os erros que obteríamos se tentássemos direcionar a saída para ~/"$f" (o que se referiria aos subdiretórios ~/data/bro_logs/2016-11-26 que provavelmente não existem em seu diretório home), removemos tudo até a barra final no nome do caminho e apenas use o nome base de cada arquivo de log.

Os sinalizadores para zgrep devem ser mencionados:

-E especifica a regex estendida, para que os parênteses em seus padrões não precisem ser escapados.

-h suprime a impressão do nome do arquivo como um prefixo para cada linha correspondente. (Você pode omitir isso na versão for do loop, já que por padrão grep apenas imprime o nome do arquivo ao pesquisar mais de um arquivo, como no primeiro comando que eu especifiquei - mas não atrapalha nada mantê-lo em ambos versões.)

-f permite que você especifique um patternfile. Isso é exatamente o que você precisa, de acordo com sua pergunta, e usar grep -f permite usar vários padrões de pesquisa de um arquivo, sem construindo um comando Awk com um grande número de "ou" s.

sort | uniq geralmente pode ser substituído por sort -u , a menos que você precise usar alguns dos sinalizadores de opção uniq . Neste caso você não, então eu usei o formulário mais simples sort -u .

    
por 27.11.2016 / 16:07

Tags