строка grep, где следующая строка не содержит строки

Я хочу искать все файлы внутри каталога и его подкаталоги для строк, содержащих определенную строку, но я хочу исключить те результаты, которые содержат определенную строку в строке сразу после нее.

Например, это:

foo1 searchString bar foo1 excludeString bar foo2 searchString bar something else foo3 searchString bar foo3 excludeString bar foo4 searchString bar 

должен вернуть это:

 foo2 searchString bar foo3 searchString bar foo4 searchString bar 

Я знаю, что -A печатает несколько строк и что -v исключает результаты. Но мой текущий подход grep -r -A 1 "searchString" | grep -v "excludeString" grep -r -A 1 "searchString" | grep -v "excludeString" явно не может работать.

Есть ли способ сказать второй grep, что он также должен удалить предыдущую строку, если найдет совпадение? Или каким-то другим способом, как я мог бы это достичь?

Производительность не является моей главной задачей; Было бы неплохо, если команда относительно легко запомнить.

Вы можете использовать следующие параметры: grep :

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

Он ищет searchString за которым следует любой символ . , повторяется ноль или более раз * , а затем новая строка \n только если нет ( ?! ) шаблона .*excludeString рядом с ним. Параметр -M присутствует, чтобы соответствовать нескольким линиям.

С sed :

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

Как это работает:

  • /searchString/!d удаляет строку, если она не соответствует searchString и читается в новой строке, снова запуская командный цикл (т.е. оставшиеся команды больше не выполняются)
  • если строка соответствует searchString , sed выполняет $!N;/\n.*excludeString/!P;D – см. ЗДЕСЬ, как это работает; разница в том, что здесь он ищет шаблон excludeString после excludeString \n ewline, так что строка, соответствующая как searchString и excludeString , все еще печатается, если за ней не следует строка, соответствующая excludeString ; если не было строки, соответствующей как searchString и excludeString (т. е. известный ввод), вы можете удалить часть \n.* и запустить:
    sed '/searchString/!d;$!N;/excludeString/!P;D' infile