Cum se poate afișa doar următoarea linie după cea care se potrivește? (Programare, Awk, Sed, Grep)

facha a intrebat.
grep -A1 'blah' logfile

Mulțumită acestei comenzi, pentru fiecare linie care conține „blah”, primesc în fișierul jurnal ieșirea liniei care conține „blah” și următoarea linie care urmează. S-ar putea să fie una simplă, dar nu găsesc o modalitate de a omite linia care are ‘blah’ și doar afișa doar linia următoare în ieșire.

Comentarii

    79

  • Cred că mulți oameni vor veni aici în căutarea de -A1 opțiunea –  > Por mirelon.
  • Apoi, eu folosesc acest lucru pentru a obține IP-ul meu public. 🙂 curl whatismyip.org | grep -A1 'Your IP Address' –  > Por shrekuu.
  • În mod similar -B1, -B2, -B3, -A1, -A2, -A3 . . . –  > Por meawoppl.
  • @shrek curl icanhazip.com (nu este nevoie de grep) 🙂 –  > Por alexyorke.
  • Site-ul tău întrebare a răspuns la întrebarea mea … -A1. Mulțumesc! –  > Por S3DEV.
12 răspunsuri
Michał Šrajer

puteți încerca cu awk:

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

Comentarii

  • Pentru oricine a vrut cu adevărat un echivalent grep -A2 (ceea ce aveam nevoie), getline doar mănâncă linia și trece la următoarea. Deci, ceea ce a funcționat pentru mine a fost literalmente doar awk '/blah/{getline; getline; print}' logfile –  > Por Aaron R..
  • Mi-a plăcut această soluție getline. –  > Por Supertech.
  • AVERTISMENT: Presupune că nu obțineți două linii potrivite una lângă alta –  > Por anthony.
Kent

Dacă doriți să rămâneți la grep:

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

sau, alternativ, cu sed:

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

Comentarii

  • @Kent, mulțumesc pentru pont. Din punctul meu de vedere, totuși, grep este mult mai ușor de citit și de înțeles în comparație cu sed sau cu răspunsul awk marcat ca fiind cel mai bun răspuns….dar poate sunt doar eu 🙂 –  > Por icasimpan.
  • Pentru cei curioși să afle ce face -v: -v –invert-match Inversează sensul de potrivire, pentru a selecta liniile care nu se potrivesc. (-v este specificat de POSIX).  > Por Sammi.
  • Îmi place foarte mult acest răspuns, dar nu va funcționa dacă aveți două linii la rând care conțin „blah” și doriți să o obțineți pe cea de-a doua (deoarece este „următoarea linie după cea care se potrivește”). Nu pot să mă gândesc la niciun caz de utilizare pentru asta din capul meu, dar merită menționat. –  > Por Vrăjitorul de tinichea.
  • Soluția de sus este pur și simplu „ok”. Dacă se întâmplă ca și a doua linie să aibă „blah” în ea, veți avea o adevărată încurcătură în mâini. –  > Por riwalk.
  • AVERTISMENT: Presupune că nu obțineți două linii identice una lângă alta. „grep” va avea atunci linii „–” în plus, în timp ce „sed” sare peste linii. DAR eu consider că această soluție „sed” este cea mai utilă atunci când nu este cazul. –  > Por anthony.
weisjohn

Piping-ul este prietenul tău…

Utilizați grep -A1 pentru a afișa următoarea linie după o potrivire, apoi trimiteți rezultatul către tail și să preia doar 1 linie,

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

Comentarii

  • Dacă „termen” este pe ultima linie, aceasta va returna linia care conține „termen” în loc de nimic, ceea ce ați dori. –  > Por Onnonymous.
  • tail -n 1 va rezulta doar ultima linie din întregul fișier –  > Por Sebastian.
souter

Minunat răspuns de la raim, mi-a fost foarte util. Este trivial să extindem acest lucru pentru a imprima de exemplu linia 7 după modelul

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

ott–

Dacă acele linii următoare nu conțin niciodată ‘blah’, le poți filtra cu:

grep -A1 blah logfile | grep -v blah

Utilizarea lui cat logfile | ... nu este necesară.

Comentarii

  • Dacă nu vă place „cat”, dar doriți numele fișierului la începutul unei conducte complexe, încercați acest lucru <logfile grep -A1 blah | grep -v blah Este perfect valabil BASH! –  > Por anthony.
fedorqui ‘SO stop harmming’

Multe răspunsuri bune au fost date până acum la această întrebare, dar încă îmi lipsește unul cu awk să nu folosești getline. De la, în general, nu este necesar să se utilizeze getline, eu aș opta pentru:

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

sau

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

Logica constă întotdeauna în memorarea liniei în care se găsește „blah” și apoi imprimarea liniilor care se află la o linie după aceasta.

Test

Fișier de probă:

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

Obțineți toate liniile de după „bla”. Aceasta tipărește un alt „bla” dacă apare după primul.

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

Obține toate liniile de după „bla” dacă nu conțin la rândul lor „bla”.

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

Comentarii

  • Aceasta este o soluție bună care gestionează liniile consecutive care se potrivesc, în cele două moduri posibile… Votată pentru completitudine! –  > Por anthony.
Travis Griggs

În general, sunt de acord că îi cereți mult lui grep aici și că un alt instrument ar putea fi o soluție mai bună. Dar, într-un mediu încorporat, s-ar putea să nu vreau să am sed sau awk doar pentru a face acest lucru. Am găsit următoarea soluție funcționează (atâta timp cât nu sunt potriviri contigue):

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

Practic, potriviți-le, adăugând 1 linie de context pentru fiecare potrivire și apoi treceți-o printr-o potrivire inversă a modelului original pentru a le elimina. Acest lucru înseamnă, desigur, că puteți presupune că modelul dvs. nu apare în linia „următoare”.

Comentarii

  • AVERTISMENT: De asemenea, scoate separatorii „–” în cazul unor rezultate multiple. –  > Por anthony.
raimue

Nu cunosc nicio modalitate de a face acest lucru cu grep, dar este posibil să folosiți awk pentru a obține același rezultat:

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

Comentarii

  • @jww Nu există nicio diferență. După cum puteți vedea din marcajele de timp care sunt la doar câteva minute distanță, se pare că am răspuns cam în același timp. –  > Por raimue.
beasy

alertă perl one-liner

doar pentru distracție… tipăriți doar o singură linie după meci

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

chiar mai distractiv… tipărește următoarele zece linii după meci

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

cam trișează totuși, deoarece sunt de fapt două comenzi

Comentarii

  • Puteți explica $.===$next? Este clar că este mai mult decât o comparație numerică a numărului liniei curente cu $next, dar nu înțeleg cum/ de ce funcționează. –  > Por Keith Bentrup.
  • Nu este mai mult decât atât. $. == $next && print este același lucru cu print if $. == $next –  > Por beasy.
  • Ah, acum înțeleg. Thx! Din cele 2 părți, fiecare este adevărată și se execută la iterații separate, adiacente ale buclei. Presupun că, dacă scopul era să tipăriți orice linie după orice potrivire, ați dori să inversați ordinea (s-ar comporta mai degrabă ca grep -A1). Dacă doriți să imprimați numai liniile următoare, dar niciodată o linie cu o potrivire, atunci ați păstra această ordine. (observând doar cum $next ar fi înfundat pentru potriviri consecutive) –  > Por Keith Bentrup.
sillyMunky

Se pare că folosești instrumentul greșit acolo. Grep nu este atât de sofisticat, cred că ar trebui să treceți la awk ca instrument pentru această sarcină:

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

Dacă aveți probleme, anunțați-mă, cred că merită să învățați puțin awk, este un instrument grozav 🙂

p.s. Acest exemplu nu câștigă un premiu pentru „utilizarea inutilă a pisicii” 😉http://porkmail.org/era/unix/award.html

Comentarii

  • BTW, puteți sări peste „$0” în print. –  > Por Michał Šrajer.
Amrit Pal Singh

grep /Pattern/ | tail -n 2 | head -n 1

Tail primele 2 și apoi head ultimul pentru a obține exact prima linie după potrivire.

lisrael1

puteți folosi grep, apoi luați liniile în salturi:
grep -A1 'blah' logfile | awk 'NR%3==2'

De asemenea, puteți lua n linii după potrivire, de exemplu:
seq 100 | grep -A3 .2 | awk 'NR%5==4'
15
25
35
45
55
65
75
85
95
explicație –
aici vrem să căutăm toate liniile care sunt *2 și să luăm 3 linii după ea, care sunt *5.
seq 100 | grep -A3 .2 vă va da:
12
13
14
15

22
23
24
25


numărul din modul (NR%5) este numărul de rânduri adăugate de grep (aici este 3 prin indicatorul -A3), +2 rânduri în plus pentru că aveți linia curentă care se potrivește și, de asemenea, linia — pe care grep o adaugă.

Tags:, ,