Як показати лише наступний рядок після відповідного?


218
grep -A1 'blah' logfile

Завдяки цій команді для кожного рядка, у якому є "blah", я отримую вихідний рядок, який містить "blah", і наступний рядок, що слідує в лог-файлі. Це може бути простим, але я не можу знайти спосіб пропустити лінію, яка має "бла" і лише показати наступний рядок у висновку.


72
Я думаю, що багато людей приїдуть сюди, шукаючи -A1варіант
мирелон

Потім я використовую це, щоб отримати свій публічний IP. :)curl whatismyip.org | grep -A1 'Your IP Address'
shrekuu

6
Аналогічно -B1, -B2, -B3, -A1, -A2, -A3. . .
meawoppl

5
@shrek curl icanhazip.com ( греп не потрібен) :)
alexyorke

1
Ваш питання відповів на моє запитання ... -A1. Дякую!
S3DEV

Відповіді:


181

ви можете спробувати з awk:

awk '/blah/{getline; print}' logfile

3
Для всіх, хто дуже хотів еквівалента grep -A2 (що саме мені потрібно), getline просто з'їдає лінію та переходить до наступної. Тож те, що працювало для мене, було буквально простоawk '/blah/{getline; getline; print}' logfile
Аарон Р.

160

якщо ви хочете дотримуватися grep:

grep -A1 'blah' logfile|grep -v "blah"

або

sed -n '/blah/{n;p;}' logfile

2
@Kent, дякую за пораду. З моєї POV, хоча, grep набагато легше зрозуміти і легко зрозуміти порівняно з sed або awk відповідь, позначена як найкраща відповідь .... але, можливо, я просто :)
icasimpan

2
Для тих, хто цікавиться, що робить -v: -v --інверт-відповідність Інвертуйте відчуття відповідності, щоб вибрати невідповідні лінії. (-v вказано POSIX.)
Саммі

2
Мені дуже подобається ця відповідь, але вона не спрацює, якщо у вас є два рядки підряд, що містять "blah" і хочете отримати другий (тому що це "наступний рядок після відповідного"). Я не можу придумати жодного випадку використання для цього вгорі голови, але це варто зазначити.
Тин Чарівник

Верхнє рішення - це просто «добре». Якщо у другому рядку також буде "благ" у ньому, у вас буде справжній безлад на руках.
riwalk

32

Піпінг - твій друг ...

Використовуйте grep -A1для показу наступного рядка після відповідності, а потім передайте результат tailі лише захоплюйте 1 рядок,

cat logs/info.log | grep "term" -A1 | tail -n 1

1
Якщо "термін" знаходиться в останньому рядку, це поверне рядок, що містить "термін" замість нічого, що ви хотіли б.
Анонім

хвіст -n 1 призведе лише до останнього рядка всього файлу
Себастьян

13

Чудова відповідь від рейду, була дуже корисною для мене. Тривіально поширити це на друк, наприклад, рядок 7 після шаблону

awk -v lines=7 '/blah/ {for(i=lines;i;--i)getline; print $0 }' logfile

9

Якщо наступні рядки ніколи не містять "blah", ви можете відфільтрувати їх за допомогою:

grep -A1 blah logfile | grep -v blah

Використання cat logfile | ...не потрібне.


5

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

grep -A1 AT\+CSQ wvdial.out | grep -v AT\+CSQ

В основному, порівнюйте їх, додаючи 1 рядок контексту для кожного матчу, а потім передайте їх через зворотну відповідність оригінальному шаблону, щоб викреслити їх. Звичайно, це означає, що ви можете припустити, що ваш шаблон не відображається у рядку "наступний".


5

На сьогодні це питання було дано багато хороших відповідей, але я все одно сумую за тим, що awkне користуюся getline. Оскільки, взагалі , користуватися не потрібно getline, я б пішов на:

awk ' f && NR==f+1; /blah/ {f=NR}' file  #all matches after "blah"

або

awk '/blah/ {f=NR} f && NR==f+1' file   #matches after "blah" not being also "blah"

Логіка завжди полягає у збереженні рядка, де знайдено "бла", а потім друкуванні тих рядків, які є одним рядком після.

Тест

Зразок файлу:

$ cat a
0
blah1
1
2
3
blah2
4
5
6
blah3
blah4
7

Отримайте всі рядки після "бла". Це друкує ще один "благ", якщо він з’являється після першого.

$ awk 'f&&NR==f+1; /blah/ {f=NR}' a
1
4
blah4
7

Отримайте всі рядки після "бла", якщо вони не містять "бла".

$ awk '/blah/ {f=NR} f && NR==f+1' a
1
4
7

5

Я не знаю жодного способу зробити це з grep, але для досягнення того ж результату можна використовувати awk:

awk '/blah/ {getline;print}' < logfile

@jww Різниці немає. Як видно з часових позначок, які знаходяться в декількох хвилинах часу, видно, що я відповів приблизно в той же час.
raimue

4

перламутровий попередження

просто для розваги ... друкуйте лише один рядок після матчу

perl -lne '$next=($.+1)if/match/;$.==$next&&print' data.txt

ще веселіше ... друкуйте наступні десять рядків після матчу

perl -lne 'push@nexts,(($.+1)..($.+10))if/match/;$.~~@nexts&&print' data.txt

своєрідне обман, однак, оскільки насправді є дві команди


Чи можете ви пояснити $. == $ далі? Зрозуміло, що це більше, ніж числове порівняння номера поточного рядка з $ next, але я не розумію, як / чому він працює.
Кіт Бентруп

Це не більше того. $. == $next && printте саме, щоprint if $. == $next
бідний

Ах, я бачу зараз. Дякую! З двох частин кожна правда і виконується на окремих суміжних ітераціях циклу. Я гадаю, якби сенс було надрукувати будь-який рядок після будь-якої відповідності, ви хотіли б змінити порядок (поводився б більше grep -A1). Якщо ви хочете надрукувати лише наступні рядки, але ніколи рядки зі збігом, ви б зберегли це в такому порядку. (лише зауваживши, як наступний долар буде покладений на наступні матчі)
Кіт Бентруп

3

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

awk '/blah/ { getline; print $0 }' logfile

Якщо у вас виникли якісь проблеми, дайте мені знати, я вважаю, що варто гарненько навчитися, це чудовий інструмент :)

ps Цей приклад не виграє "марне використання котячої нагороди";) http://porkmail.org/era/unix/award.html


3
До речі, ви можете пропустити друк "$ 0".
Michał Šrajer

0

grep / Шаблон / | хвіст -n 2 | голова -n 1

Хвост спочатку 2, а потім головою останнього, щоб отримати точно перший рядок після матчу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.