Як я можу скласти каталог на основі вмісту двох послідовних рядків?


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.

EDIT: Як було вказано на маніпуляції , є деякі проблемні випадки, яких слід дотримуватися. Хоча цікавий виклик через grepфункціонально орієнтовану лінійку, будь-яке рішення з ним, швидше за все, буде «злом», і вам, ймовірно, краще використовувати щось подібне, pcregrepщо більше підходить до заданої задачі.


Приємно. Я хоч і запитав про каталог; це, здається, працює:find . -name '*.txt' | xargs grep -A1 'Foo' | grep -B1 'Bar'
Натан Лонг

Це також буде перераховувати події з "Foo" і "Bar" в одному рядку.
манатура

@manatwork: Рядки, що містять "Foo" і "Bar", - це "рядки, що містять" Foo "", про що було запропоновано.
цейробинсон

1
@tojrobinson, а як бути ", але отримуйте збіги лише тоді, коли наступний рядок також містить" Bar "? pastebin.com/Yj8aeCEA
манатура

3

Хоча я віддаю перевагу використанню рішення Натана 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

1
Класна хитрість що -z. Деякі "(. *)" До і після всього виразу змушують його виводити всі відповідні рядки. На даний момент підрядки перед "Foo" та після "Bar" не відображаються.
манатство

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.