Как я могу получить каталог на основе содержимого двух последовательных строк?


11

Как я могу найти каталог для строк, которые содержат «Foo», но получать совпадения только тогда, когда следующая строка также содержит «Bar»?


Проблема теперь полностью отличается от оригинала: / Может быть, лучше вернуть старые версии и ПОСТАВИТЬ еще одну? Более того, новый вопрос мне не понятен.
Жиль Квено

@sputnick - как так? Я указал каталог, когда впервые опубликовал вопрос; Я только смел, потому что люди не замечали.
Натан Лонг

Неважно, что будет работать, я буду редактировать мой POST соответственно.
Жиль Квено

Ответы:


7

@ warl0ck указал мне правильное направление pcregrep, но я сказал «содержит», а не «есть», и я спросил о каталоге, а не о файле.

Кажется, это работает для меня.

pcregrep -rMi 'Foo(.*)\n(.*)Bar' .

6

Сам Grep не поддерживает его, вместо этого используйте pcregrep:

Foo
Bar
Foo
abc

pcregrep -M "Foo\nBar" file

Получил:

Foo
Bar

3
ОП не сказал этого Fooи Barбудет включать в себя всю линию.
Тойробинсон

6

С помощью sedскрипта:

#!/bin/sed -nf

/^Foo/{
    h         # put the matching line in the hold buffer
    n         # going to nextline
    /^Bar/{   # matching pattern in newline
        H     # add the line to the hold buffer
        x     # return the entire paragraph into the pattern space
        p     # print the pattern space
        q     # quit the script now
    }
}

Чтобы использовать это:

chmod +x script.sed
printf '%s\n' * | ./script.sed

printfЗдесь отображаются все файлы в текущей директории на одной строке каждого, и передать его sed.

Примечание : это отсортировано по алфавиту.

Больше информации полезно pattern spaceи hold space ЗДЕСЬ .

У grymoire.com есть действительно хорошие вещи о shellпрограммировании.


Что h, n, H, x, p, qзначит? Очень интересно.
Яманеко

Смотрите мои комментарии. Больше информации на pattern space& hold space: grymoire.com/Unix/Sed.html#uh-56 или на французском commentcamarche.net/faq/9536-sed-introduction-a-sed-part-i
Жиль Квено

POST адаптирован для работы с каталогом
Gilles Quenot

4

Используя grepтолько, вы можете построить следующую трубу:

grep -A1 'Foo' input_file | grep -B1 'Bar' | grep 'Foo'

Первый grepполучит все строки, которые содержат, Fooа также строку после матча. Затем мы получаем строки, которые содержат Barкак и строку перед совпадением, и, наконец, извлекают строки из этого вывода, которые содержат Foo.

РЕДАКТИРОВАТЬ: Как указал manatwork , есть некоторые проблемные случаи, которые следует соблюдать. Хотя это интересная задача, благодаря grepлинейно-ориентированной функциональности, любое решение с ней, скорее всего, будет «взломом», и вам, вероятно, лучше использовать что-то подобное, pcregrepболее подходящее для поставленной задачи.


Ницца. Я спросил о каталоге, хотя; это, кажется, работает:find . -name '*.txt' | xargs grep -A1 'Foo' | grep -B1 'Bar'
Натан Лонг

Это также будет перечислять случаи с «Foo» и «Bar» в одной строке.
manatwork

@manatwork: строки, содержащие «Foo» и «Bar», являются «строками, которые содержат« Foo »», что и было задано.
Тойробинсон

1
@tojrobinson, а как насчет «но получать совпадения только в том случае, если следующая строка также содержит часть« Бар »»? pastebin.com/Yj8aeCEA
manatwork

3

Хотя я предпочитаю использовать решение Натана pcregrep, вот решение с использованием только grep

grep -o -z -P  'Foo(.*)\n(.*)Bar' file

Варианты объяснения:

  • -oпечатать только соответствующую часть. Необходимо, так как включение -zраспечатает весь файл (если где-то нет \ 0)
  • -z Обрабатывайте ввод как набор строк, каждая из которых заканчивается нулевым байтом (символ ASCII NUL) вместо новой строки.
  • -P Синтаксис регулярных выражений Perl

РЕДАКТИРОВАТЬ: эта версия печатает целые совпавшие строки

    grep -o -P -z  '(.*)Foo(.*)\n(.*)Bar(.*)' file

1
Прикольный трюк какой -z. Некоторые «(. *)» До и после всего выражения заставят его вывести все совпадающие строки. На данный момент подстроки до «Foo» и после «Bar» не отображаются.
manatwork

1

С awk:

awk '/bar/ && prev != "" {print FILENAME ": " prev "\n" FILENAME ": " $0}
     /foo/ {prev=$0; next}
     {prev=""}' file1...

(общее примечание об ограничении awk: учтите, что если некоторые имена файлов могут содержать символы "=", вам нужно будет передавать их как ./filenameвместо filenameawk)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.