Як я можу зірвати каталог для рядків, що містять "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
.
EDIT: Як було вказано на маніпуляції , є деякі проблемні випадки, яких слід дотримуватися. Хоча цікавий виклик через 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
синтаксис perge regex EDIT: Ця версія друкує цілі відповідні рядки
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)