Como imprimir apenas uma correspondência de grep quando tail -f?

5

Estou lendo um log ativo e tentando obter algumas chamadas especiais

$ tail -f example.log | egrep 'pattern1|pattern2|pattern3|pattern4|pattern5'

Mas alguns padrões mal são impressos (devido ao fluxo dev) e os outros são impressos de forma muito contínua.

Como posso fazer com que egrep imprima apenas uma solicitação para cada padrão, para que eu possa ver facilmente que eles estão funcionando bem.

    
por tachomi 03.08.2016 / 21:27

3 respostas

6

Você pode fazer algo como:

tail -f example.log | awk '
  BEGIN {
    n = split("pattern1,pattern2,pattern3,pattern4,pattern5", pats, /,/)
  }
  {
    found=0
    for (i in pats) if ($0 ~ pats[i]) {
      found=1
      delete pats[i]
      n--
    }
  }
  found {print; if (!n) exit}'

Observe que awk sairá assim que tiver visto todos os padrões, mas tail só sairá (de um SIGPIPE) somente na próxima vez que escrever algo depois disso.

Ou se as linhas não corresponderem a vários padrões e se você não se importar em sair quando todos os padrões forem encontrados, mais curtos, mas menos eficientes:

awk '/pattern1/&&!a++ || /pattern2/&&!b++ || /pattern3/&&!c++ || \
     /pattern4/&&!d++ || /pattern5/&&!e++'

Com zsh e GNU grep :

(trap '' PIPE;tail -f example.log > >(grep -m1 pattern1) \
                                  > >(grep -m1 pattern2) \
                                  > >(grep -m1 pattern3) \
                                  > >(grep -m1 pattern4) \
                                  > >(grep -m1 pattern5))

Mas observe que as linhas que correspondem a vários padrões serão impressas quantas vezes.

    
por 03.08.2016 / 21:41
1

Acredito que você esteja atrás de -o , que imprimirá apenas a parte correspondente. Então você poderia fazer o seguinte:

cat example.log | egrep -o 'pat1|pat2|pat3|pat4|pat5' | sort | uniq

Se a saída contiver um padrão, é porque pelo menos uma linha corresponde a esse padrão. Se a saída contiver todos os 5 padrões, cada padrão corresponderá a pelo menos uma linha.

Não funciona com expressões regulares que podem corresponder diferentes caracteres ou diferentes correspondências de tamanho.

    
por 03.08.2016 / 21:44
1

Outra abordagem poderia ser produzir as linhas correspondentes a cada padrão em relação à anterior em sua própria linha, como:

#! /bin/sh
tput rmam # no line wrap for terminals that can do it
awk -v u="$(tput cuu1)" -v el="$(tput el)" '
  BEGIN {
    for (n = 0; n < ARGC; n++) pat[n] = ARGV[n]
    ARGC=0
  }
  {
    pre = ""; post = el "\r" u
    for (i = 1; i < n; i++) {
      if ($0 ~ pat[i]) print pre $0 post
      pre = pre "\n"
      post = post u
    }
  }
  END{printf "%s", pre}' "$@"
tput smam

Chamado como:

tail -f example.log | that-script pattern1 pattern2...

Exemplo:

    
por 04.08.2016 / 08:35