grep para "termo" e excluir "outro termo"

22

Eu estou tentando construir uma pesquisa grep que procura por um termo, mas exclui as linhas que têm um segundo termo. Eu queria usar várias opções de -e "pattern" , mas isso não funcionou.

Aqui está um exemplo de um comando que eu tentei e a mensagem de erro que ele gerou.

grep -i -E "search term" -ev "exclude term"
grep: exclude term: No such file or directory

Parece-me que o -v se aplica a todos os termos / padrões de pesquisa. Como isso é executado, mas não inclui search term nos resultados.

grep -i -E "search term" -ve "exclude term"
    
por nelaaro 17.01.2013 / 11:26

4 respostas

36

Para expressões e com o grep, você precisa de duas invocações:

grep -Ei "search term" | grep -Eiv "exclude term"

Se os termos que você está procurando não forem expressões regulares, use a correspondência de cadeia fixa ( -F ) que é mais rápida:

grep -F "search term" | grep -Fv "exclude term"
    
por 17.01.2013 / 11:31
11

Faltando duas vezes para o grep, só consigo pensar em uma maneira de conseguir isso. Envolve Expressões Regulares Compatíveis com Perl (PCRE) e algumas bem hacky asserções de vista geral .

Para pesquisar foo excluindo correspondências que contenham barra , você pode usar:

grep -P '(?=^((?!bar).)*$)foo'

Veja como funciona:

  • (?!bar) corresponde a qualquer coisa que não barra sem consumir caracteres da string. Então . consome um único caractere.

  • ^((?!bar).)* repete o que foi mencionado acima desde o início da sequência ( ^ ) até o final dela ( $ ). Ele falhará se bar for encontrado em um determinado ponto, pois (?!bar) não corresponderá.

  • (?=^((?!bar).)*$) garante que a string corresponda ao padrão anterior, sem consumir caracteres da string.

  • foo procura por foo como de costume.

Encontrei este hack em Expressão regular para corresponder a string que não contém uma palavra? . Em A resposta de Bart Kiers , você pode encontrar uma explicação muito mais detalhada de como o look-ahead negativo opera.

    
por 17.01.2013 / 11:51
8

Se você quiser fazer isso em um passo, você pode usar awk ao invés de grep.

Formato:

echo "some text" | awk '/pattern to match/ && !/pattern to exclude/'

Exemplos:

  • echo "hello there" | awk '/hello/ && !/there/'

Não retorna nada.

  • echo "hello thre" | awk '/hello/ && !/there/'

Retorna: olá thre

  • echo "hllo there" | awk '/hello/ && !/there/'

Não retorna nada.

Para vários padrões, você pode usar parênteses para agrupá-los.

Exemplos:

  • echo "hello thre" | awk '(/hello/ || /hi/) && !/there/'

Retorna: olá thre

  • echo "hi thre" | awk '(/hello/ || /hi/) && !/there/'

Retorna: oi thre

  • echo "hello there" | awk '(/hello/ || /hi/) && !/there/'

Não retorna nada.

  • echo "hi there" | awk '(/hello/ || /hi/) && !/there/'

Não retorna nada.

    
por 25.05.2017 / 05:18
1

Das minhas experiências, não faz muita diferença se você canaliza seus termos de exclusão através de grep ou sed . Sed tem alguns outros recursos úteis de substituição de texto que eu costumo usar para filtrar melhor a saída de arquivos de log. Então eu vou usar o sed enquanto eu combino um grande número de filtros no sed.

wc /var/log/tomcat/tomcat.2013-01-14.log.1 
  1851725

 /usr/bin/time grep -i -E "(loginmanager)" /var/log/tomcat/tomcat.2013-01-14.log.1 | sed -e "/login OK/d" -e "/Login expired/d" | wc
24.05user 0.15system 0:25.27elapsed 95%CPU (0avgtext+0avgdata 3504maxresident)k
0inputs+0outputs (0major+246minor)pagefaults 0swaps
   5614   91168 1186298

 /usr/bin/time grep -i -E "(loginmanager)" /var/log/tomcat/tomcat.2013-01-14.log.1 | sed -e "/login OK/d" -e "/Login expired/d" | wc
23.50user 0.16system 0:24.48elapsed 96%CPU (0avgtext+0avgdata 3504maxresident)k
0inputs+0outputs (0major+246minor)pagefaults 0swaps
   5614   91168 1186298

 /usr/bin/time grep -i -E "(loginmanager)" /var/log/tomcat/tomcat.2013-01-14.log.1 | grep -v -e "login OK" -e "Login expired" | wc
23.08user 0.14system 0:23.55elapsed 98%CPU (0avgtext+0avgdata 3504maxresident)k
0inputs+0outputs (0major+246minor)pagefaults 0swaps
   5614   91168 1186298

 /usr/bin/time grep -i -E "(loginmanager)" /var/log/tomcat/tomcat.2013-01-14.log.1 | grep -v -e "login OK" -e "Login expired" | wc
23.50user 0.15system 0:25.27elapsed 93%CPU (0avgtext+0avgdata 3488maxresident)k
0inputs+0outputs (0major+245minor)pagefaults 0swaps
   5614   91168 1186298

    
por 17.01.2013 / 11:43