Imprime estatísticas de um arquivo de texto

4

Eu tenho um arquivo de texto (events.dat) como este abaixo (observe apenas uma extração é mostrada)

RepID12 01/01/2010 20:56:00 S10
RepID12 01/01/2010 20:56:00 S03
RepID20 01/01/2010 20:56:00 S17
RepID33 01/01/2010 20:56:00 S02
RepID33 01/01/2010 20:56:00 S18
RepID38 01/01/2010 20:56:00 S11
RepID39 01/01/2010 20:56:00 S20
RepID26 02/01/2010 01:39:00 S20
RepID29 02/01/2010 01:39:00 S16
RepID29 02/01/2010 01:39:00 S03
RepID22 02/01/2010 01:39:09 S01
RepID26 02/01/2010 01:39:09 S02
RepID40 02/01/2010 01:39:18 S02
RepID38 02/01/2010 01:39:09 S05
RepID31 02/01/2010 01:39:09 S06
RepID31 02/01/2010 01:39:09 S08
RepID09 02/01/2010 01:39:09 S09
RepID23 02/01/2010 01:39:18 S09
RepID19 02/01/2010 01:40:09 S09
RepID21 02/01/2010 01:40:18 S09
RepID28 02/01/2010 01:40:27 S09
RepID43 02/01/2010 01:40:09 S14

e assim por diante, cobrindo eventos por um período total de 48 horas. Gostaria de imprimir apenas as linhas quando forem encontrados mais de 60 eventos por minuto.

Por exemplo, com este comando, posso contar quantos eventos existem em um minuto específico:

grep "02/01/2010 01:39" events.dat | wc -l

e isso retornará 60 (por exemplo) que deve ser o número máximo de eventos / min.

Como posso fazer o mesmo, mas verificando cada minuto durante as 48 horas inteiras e imprimo somente as linhas onde mais de 60 eventos / min são encontrados? thx antecipadamente

    
por Dad85 20.12.2016 / 11:07

4 respostas

1

Com algo assim, você pode isolar os minutos disponíveis:

root@debian:# awk -F" " '{print $2" "$3}' b.txt |cut -f1-2 -d: |uniq
01/01/2010 20:56
02/01/2010 01:39
02/01/2010 01:40
02/01/2010 20:56

Você pode então atribuir um array com esses valores

Código revisado:

readarray -t stamps < <(awk -F" " '{print $2" "$3}' b.txt |cut -f1-2 -d: |uniq)
for stamp in "${stamps[@]}";do
ev=$(grep "$stamp" b.txt |wc -l)
echo "In $stamp found $ev events "
#if [ "$ev" -gt 60 ]; then
# do the stuff
#fi
done

Saída:

In 01/01/2010 20:56 found 7 events 
In 02/01/2010 01:39 found 11 events 
In 02/01/2010 01:40 found 4 events 
In 02/01/2010 20:56 found 7 events 
    
por 20.12.2016 / 11:32
4

O ideal seria tentar processar o arquivo apenas uma vez e armazenar o mínimo na memória. Em awk , você poderia fazer:

awk -v n=60 '
  {
    t = $2 substr($3, 1, 5);
    if (t == last_t) {
      if (++lines > n)
        print
      else
        if (lines == n)
          print saved $0
        else
          saved = saved $0 RS
    } else {
      saved = $0 RS
      lines = 1
      last_t = t
    }
  }' < your-file

Algumas vantagens com essa abordagem:

  • Isso é orientado para processamento de fluxo. A entrada é processada assim que ocorre e a saída é emitida o mais rápido possível (assim que a 60ª linha for vista). Isso possibilita a pós-processamento da saída ao vivo do processo (como em tail -fn +1 log_file ).
  • ele executa apenas uma chamada de um comando ( awk ), portanto, será tão eficiente quanto possível. O extremo oposto seria executar vários comandos em um loop . O mais caro em scripts de shell é geralmente bifurcar e executar comandos. Otimizar significa reduzir isso o máximo possível.
  • armazenamos no máximo 60 linhas na memória para que o uso da memória seja vinculado (desde que o tamanho das próprias linhas esteja vinculado).
  • O código

    awk pode ser muito legível e autoexplicativo. Agora, se o tamanho é o problema, você também pode torná-lo mais curto e em uma linha como

    awk '{t=$2substr($3,1,5);if(t==l){if(++i>n)print;else if(i==n)print s$0;else s=s$0RS}else{s=$0RS;i=1;l=t}}' n=60 file
    
por 20.12.2016 / 12:12
2

Esta não é a solução mais eficiente, mas você pode primeiro contar o número de eventos para cada minuto e, em seguida, grep seu arquivo para cada um desses minutos quando a contagem for > = 60.

sort -k 2,3 your_log_file \
| uniq -c -s 8 -w 16 \
| while read count _ date time _; do
    [ "$count" -ge 60 ] && grep -F " $date ${time%:*}" your_log_file
done

Notas:

  • no exemplo básico acima, eu primeiro organizei seu arquivo cronologicamente
  • as primeiras duas linhas fornecerão o número de eventos por minuto, se essa for a única informação que lhe interessa.

Se o seu arquivo estiver cheio de eventos, é provável que você acabe fazendo vários grep s nele. Uma solução melhor seria ler o arquivo de log sequencialmente e memorizar as linhas do último minuto. Quando chegar ao próximo minuto, imprima estas linhas se o seu número for maior que 60. Veja a resposta de Stéphane para tal solução.

    
por 20.12.2016 / 11:37
1
awk '{ print $2 " " $3 }' < input \
| cut -c1-16                      \
| sort                            \
| uniq -c                         \
| awk '{ if ($1 > 60) print $2 }'

i.e. obtenha os campos de data e hora, retire os segundos, classifique o resultado (NB: funcionaria melhor se as datas estivessem no formato ISO), encontre a contagem de cada combinação única de data / hora e imprima os com uma contagem > 60

    
por 20.12.2016 / 15:36