Jak wyświetlić tylko następny wiersz po dopasowanym?

218
grep -A1 'blah' logfile

Dzięki temu poleceniu dla każdej linii, która zawiera „bla”, otrzymuję wynik linii zawierającej „bla” i kolejną linię, która następuje w pliku dziennika. Może to być proste, ale nie mogę znaleźć sposobu na pominięcie wiersza zawierającego słowo „bla” i wyświetlenie tylko następnego wiersza na wyjściu.

facha
źródło
72
Myślę, że wiele osób przyjedzie tutaj w poszukiwaniu -A1opcji
mirelon
Następnie używam tego, aby uzyskać moje publiczne IP. :)curl whatismyip.org | grep -A1 'Your IP Address'
shrekuu,
6
Podobnie -B1, -B2, -B3, -A1, -A2, -A3. . .
meawoppl
5
@shrek curl icanhazip.com (nie wymaga grep) :)
alexyorke
1
Twoje pytanie odpowiedziałeś na moje pytanie ... -A1. Dzięki!
S3DEV,

Odpowiedzi:

181

możesz spróbować z awk:

awk '/blah/{getline; print}' logfile
Michał Šrajer
źródło
3
Dla każdego, kto naprawdę chciał ekwiwalentu grep-A2 (czego potrzebowałem), getline po prostu zjada linię i przechodzi do następnego. Tak więc, co zadziałało dla mnie, było dosłownieawk '/blah/{getline; getline; print}' logfile
Aaron R.
160

jeśli chcesz trzymać się grep:

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

lub

sed -n '/blah/{n;p;}' logfile
Kent
źródło
2
@Kent, dzięki za wskazówkę. Z mojego POV jednak grep jest znacznie bardziej czytelny i łatwiejszy do zrozumienia w porównaniu do sed lub odpowiedzi awk oznaczonej jako najlepsza odpowiedź .... ale to tylko ja być może :)
icasimpan
2
Dla ciekawiących, co robi -v: -v --invert-match Odwraca sens dopasowania, aby wybrać niepasujące linie. (-v jest określony przez POSIX.)
Sammi
2
Naprawdę podoba mi się ta odpowiedź, ale nie zadziała, jeśli masz dwa wiersze w wierszu zawierające „bla” i chcesz uzyskać drugi (ponieważ jest to „następny wiersz po dopasowanym”). Nie mogę wymyślić żadnego przypadku użycia tego z głowy, ale warto to zauważyć.
Tin Wizard
Najlepsze rozwiązanie jest po prostu „ok”. Jeśli zdarzy się, że w drugiej linii jest też „bla”, będziesz miał prawdziwy bałagan na rękach.
riwalk
32

Rurociągi to twój przyjaciel ...

Użyj, grep -A1aby wyświetlić kolejną linię po meczu, a następnie przesuń wynik do taili złap tylko 1 linię,

cat logs/info.log | grep "term" -A1 | tail -n 1
weisjohn
źródło
1
Jeśli „termin” znajduje się w ostatnim wierszu, spowoduje to zwrócenie wiersza zawierającego „termin” zamiast niczego, czego byś chciał.
Onnonim
tail -n 1 spowoduje tylko ostatni wiersz całego pliku
Sebastian
13

Świetna odpowiedź od Raima, była dla mnie bardzo przydatna. Rozbudowanie tego jest trywialne, np. Wiersz 7 po wzorze

awk -v lines=7 '/blah/ {for(i=lines;i;--i)getline; print $0 }' logfile
router
źródło
9

Jeśli następne wiersze nigdy nie zawierają „bla”, możesz je filtrować za pomocą:

grep -A1 blah logfile | grep -v blah

Korzystanie z cat logfile | ...nie jest potrzebne.

ott--
źródło
5

Ogólnie rzecz biorąc, zgadzam się, że pytasz tutaj o grep i że innym narzędziem może być lepsze rozwiązanie. Ale w środowisku osadzonym może nie chcę tego robić sedlub awkpo prostu to robić. Odkryłem, że działa następujące rozwiązanie (o ile nie są to ciągłe dopasowania):

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

Zasadniczo dopasuj je, dodając 1 linię kontekstu dla każdego dopasowania, a następnie przeprowadź go przez odwrotne dopasowanie oryginalnego wzoru, aby je usunąć. To oczywiście oznacza, że ​​możesz założyć, że twój wzór nie pojawia się w „następnym” wierszu.

Travis Griggs
źródło
5

Do tej pory udzielono wielu dobrych odpowiedzi na to pytanie, ale wciąż brakuje mi jednej z nich, gdy się awknie korzysta getline. Ponieważ, ogólnie rzecz biorąc , nie jest konieczne użycie getline, wybrałbym:

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

lub

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

Logika zawsze polega na zapisaniu wiersza, w którym znajduje się „bla”, a następnie wydrukowaniu tych wierszy, które są po jednym wierszu.

Test

Przykładowy plik:

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

Zdobądź wszystkie linie po „bla”. To wypisuje kolejne „bla”, jeśli pojawia się po pierwszym.

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

Zdobądź wszystkie wiersze po „bla”, jeśli same nie zawierają „bla”.

$ awk '/blah/ {f=NR} f && NR==f+1' a
1
4
7
fedorqui „SO przestań szkodzić”
źródło
5

Nie wiem, jak to zrobić za pomocą grep, ale można użyć awk, aby osiągnąć ten sam wynik:

awk '/blah/ {getline;print}' < logfile
raimue
źródło
@jww Nie ma różnicy. Jak widać na podstawie znaczników czasu, które dzieli zaledwie kilka minut, wydaje się, że odpowiedziałem mniej więcej w tym samym czasie.
raimue
4

Perl One-Liner Alert

tylko dla zabawy ... drukuj tylko jedną linię po meczu

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

jeszcze więcej zabawy ... wydrukuj kolejne dziesięć linii po meczu

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

trochę oszustwo, ponieważ tak naprawdę są dwa polecenia

beasy
źródło
Czy możesz wyjaśnić $. == $ dalej? Oczywiście jest to więcej niż liczbowe porównanie bieżącego numeru wiersza z $ next, ale nie rozumiem, jak / dlaczego to działa.
Keith Bentrup
To nic więcej. $. == $next && printjest taki sam jakprint if $. == $next
beasy
Ach, rozumiem teraz. Dzięki! Z 2 części każda jest prawdziwa i działa na osobnych, sąsiadujących iteracjach pętli. Podejrzewam, że jeśli chodzi o wydrukowanie dowolnej linii po jakimkolwiek dopasowaniu, chciałbyś odwrócić kolejność (zachowałby się bardziej jak grep -A1). Jeśli chcesz wydrukować tylko kolejne wiersze, ale nigdy nie pasuje do dopasowania, zachowaj tę kolejność. (tylko zwracając uwagę na to, że $ next będzie zdobyte przez kolejne mecze)
Keith Bentrup
3

Wygląda na to, że używasz niewłaściwego narzędzia. Grep nie jest tak wyrafinowany, myślę, że chcesz skorzystać z awk jako narzędzia do tego zadania:

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

Jeśli pojawią się jakiekolwiek problemy, daj mi znać, myślę, że warto nauczyć się trochę awk, to świetne narzędzie :)

ps Ten przykład nie wygrywa „bezużytecznego wykorzystania nagrody kota”;) http://porkmail.org/era/unix/award.html

sillyMunky
źródło
3
BTW, możesz pominąć „0 $” w druku.
Michał Šrajer
0

grep / Pattern / | ogon -n 2 | głowa -n 1

Ogon pierwszy 2, a następnie ostatni, aby uzyskać dokładnie pierwszą linię po meczu.

Amrit Pal Singh
źródło