Как я могу найти каталог для строк, которые содержат «Foo», но получать совпадения только тогда, когда следующая строка также содержит «Bar»?
Как я могу найти каталог для строк, которые содержат «Foo», но получать совпадения только тогда, когда следующая строка также содержит «Bar»?
Ответы:
@ warl0ck указал мне правильное направление pcregrep
, но я сказал «содержит», а не «есть», и я спросил о каталоге, а не о файле.
Кажется, это работает для меня.
pcregrep -rMi 'Foo(.*)\n(.*)Bar' .
Сам Grep не поддерживает его, вместо этого используйте pcregrep:
Foo
Bar
Foo
abc
pcregrep -M "Foo\nBar" file
Получил:
Foo
Bar
Foo
и Bar
будет включать в себя всю линию.
С помощью 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
Используя 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'
Хотя я предпочитаю использовать решение Натана 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
-z
. Некоторые «(. *)» До и после всего выражения заставят его вывести все совпадающие строки. На данный момент подстроки до «Foo» и после «Bar» не отображаются.
С awk:
awk '/bar/ && prev != "" {print FILENAME ": " prev "\n" FILENAME ": " $0}
/foo/ {prev=$0; next}
{prev=""}' file1...
(общее примечание об ограничении awk: учтите, что если некоторые имена файлов могут содержать символы "=", вам нужно будет передавать их как ./filename
вместо filename
awk)