Як підключити текст у файлі та відобразити абзац, у якому є текст?


24

Нижче текст у файлі:

Pseudo name=Apple
Code=42B
state=fault

Pseudo name=Prance
Code=43B
state=good

Мені потрібно поздоровитись на "42B" та отримати вихід із тексту, описаного вище:

Pseudo name=Apple
Code=42B
state=fault

Хтось має уявлення про те, як цього досягти за допомогою grep/ awk/ sed?


Ви позначили це питання просто "грепом". Ви тоді шукаєте лише рішення "grep"? У питанні ви також вказуєте awk & sed. Чи можемо ми додати ці теги? Я не був впевнений у вашому намірі, коли минулого вечора я редагував питання.
slm

Відповіді:


38

З awk

awk -v RS='' '/42B/' file

RS=змінює роздільник записів на вхід з нового рядка на порожні рядки. Якщо будь-яке поле запису містить /42B/друк запису.

''(нульовий рядок) - це магічне значення, яке використовується для представлення порожніх рядків відповідно до POSIX :

Якщо RS є нульовим, тоді записи розділені послідовностями, що складаються з <newline>плюс однієї чи декількох порожніх рядків, провідні або проміжні порожні рядки не повинні призводити до порожніх записів на початку або в кінці вводу, а a <newline>завжди повинен бути роздільником поля, незалежно від значення FS .

Абзаци виводу не відокремлюються, оскільки розділювачем виходу залишається один новий рядок. Щоб переконатися, що між абзацами виведення є порожній рядок, встановіть роздільник запису виводу на два нові рядки:

awk -v RS='' -v ORS='\n\n' '/42B/' file

1
+1 для елегантного рішення. Не потрібно перенаправляти файл, хоча ...
jasonwryan

пальці були на автопілоті.
llua

2
@jasonwryan, якщо вам не потрібен доступ до імені файлу в межах awk ( FILENAME), це не погана ідея використовувати перенаправлення, оскільки це дозволяє уникнути проблем із назвою файлу, що містить =або починається з -(або є -), створює послідовні повідомлення про помилки та уникає запуску awkчи виконання інші перенаправлення, якщо вхідний файл неможливо відкрити.
Стефан Шазелас

14

Припустимо, що дані структуровані так, що це завжди лінія до і після цього, яку ви хочете, ви можете використовувати перемикачі grep -A(після) та -B(до), щоб сказати, що вона включає 1 рядок перед матчем та 1 рядок після нього:

$ grep -A 1 -B 1 "42B" sample.txt
Pseudo name=Apple
Code=42B
state=fault

Якщо вам потрібні однакові рядки до і після пошукового терміну, ви можете скористатися -C(контекстним) перемикачем:

$ grep -C 1 "42B" sample.txt
Pseudo name=Apple
Code=42B
state=fault

Якщо ви хочете бути більш суворими при збігу декількох рядків, ви можете скористатися інструментом pcregrep, щоб відповідати шаблону по декількох рядках:

$ pcregrep -M 'Pseudo.*\n.*42B.*\nstate.*' sample.txt
Pseudo name=Apple
Code=42B
state=fault

Наведений вище зразок відповідає наступному:

  • -M - кілька рядків
  • 'Pseudo.*\n.*42B.*\nstate.*'- відповідає групі рядків, де перша рядок починається зі слова, "Pseudo"за яким слідують будь-які символи до кінця рядка \n, а потім будь-які символи вгору до тих пір, поки рядок не "42B"супроводжується будь-якими символами до іншого кінця рядка ( \n), а потім рядок "state"слідом за будь-якими символами.

5
-C(контекст) може використовуватися як ярлик, якщо -Aі -Bоднаковий.
Девід Баггерман

@DavidBaggerman - спасибі Додав його до відповіді.
slm

Чому голосуючий "проти"? Це відповідає на питання.
slm

4

Напевно, існує подібний простий спосіб зробити це з awk, але в перл:

cat file | perl -ne 'BEGIN { $/="\n\n" }; print if $_ =~ /42B/;'

Це в основному означає розділити файл на шматки, розміщені порожніми рядками, а потім друкувати лише ті фрагменти, які відповідають вашому регулярному вираженню.


10
Це можна спростити, використовуючи параметри та скорочення, і втратити марне використанняcat ; perl -00 -ne 'print if /42B/' file
tripleee

4

У grepдеяких ароматах Unix є -pпрапор "абзацу". Я знаю, що AIX робить .

grep -p 42B <myfile>

зробив би саме те, чого ви там просите. YMMV та GNU grep не мають цього прапора.


Мати прапор -p було б чудово. Особливо, якщо їх використовувати разом з -v, щоб ви могли виключити цілі абзаци з виводу.
IllvilJa

2

Інше рішення Perl, без останнього порожнього рядка:

perl -00ne 'if ($_ =~ /42B/) {chomp($_); printf "%s\n",$_}' foo

Приклад

% perl -00ne 'if ($_ =~ /42B/) {chomp($_); printf "%s\n",$_}' foo
Pseudo name=Apple
Code=42B
state=fault

% cat foo
Pseudo name=Apple
Code=42B
state=fault

Pseudo name=Prance
Code=43B
state=good

1
Або коротше (і , отже , більш зручним для читання), а triplee написав в коментарі: perl -00 -ne 'print if /42B/' file.
mivk
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.