grep string onde a próxima linha não contém string

5

Eu quero pesquisar todos os arquivos dentro de um diretório e seus subdiretórios por linhas que contenham uma certa string, mas eu quero excluir os resultados que contenham uma determinada string na linha imediatamente depois dela.

Por exemplo, isso:

foo1 searchString bar
foo1 excludeString bar

foo2 searchString bar
something else

foo3 searchString bar

foo3 excludeString bar

foo4 searchString bar

deve retornar isso:

foo2 searchString bar
foo3 searchString bar
foo4 searchString bar

Eu sei que -A imprime várias linhas e que -v exclui resultados. Mas minha abordagem atual de grep -r -A 1 "searchString" | grep -v "excludeString" obviamente não funciona.

Existe uma maneira de dizer ao segundo grep que ele também deve remover a linha anterior se encontrar uma correspondência? Ou de alguma outra forma como eu poderia conseguir isso?

O desempenho não é minha principal preocupação; Seria bom se o comando fosse relativamente fácil de lembrar.

    
por tim 05.08.2015 / 16:22

2 respostas

7

Você pode usar p erl c ompatível r egular e xpressões grep :

$ pcregrep -M '(searchString.*\n)(?!.*excludeString)' file
foo2 searchString bar
foo3 searchString bar
foo4 searchString bar

Ele procura searchString seguido por qualquer caractere . , repetido zero ou mais vezes * , seguido pela nova linha \n somente se houver não ( ?! ) padrão .*excludeString próximo a ele. A opção -M está presente para corresponder a várias linhas.

    
por 05.08.2015 / 16:37
6

com sed :

sed '/searchString/!d;$!N;/\n.*excludeString/!P;D' infile

Como funciona:

  • /searchString/!d exclui a linha se ela não corresponder a searchString e ler em uma nova linha, iniciando o ciclo de comando novamente (isto é, os comandos restantes não são mais executados)
  • se a linha corresponder a searchString , sed executa $!N;/\n.*excludeString/!P;D - consulte AQUI como funciona; A diferença é que, aqui, ele está procurando pelo padrão excludeString após o caractere \n ewline, de forma que uma linha correspondente a searchString e excludeString ainda seja impressa se não for seguida por uma linha correspondente a excludeString ; se não houvesse correspondência de linha entre searchString e excludeString (ou seja, entrada conhecida), você poderia descartar a parte \n.* e executar:% sed '/searchString/!d;$!N;/excludeString/!P;D' infile
por 05.08.2015 / 16:51