Як я можу зірвати каталог для рядків, що містять "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замість filenameawk)