Come mostrare solo la riga successiva dopo quella abbinata?


218
grep -A1 'blah' logfile

Grazie a questo comando per ogni riga che contiene 'blah', ottengo l'output della riga che contiene 'blah' e la riga successiva che segue nel file di log. Potrebbe essere semplice ma non riesco a trovare un modo per omettere la riga che ha "blah" e mostrare solo la riga successiva nell'output.


72
Penso che molte persone verranno qui in cerca -A1dell'opzione
mirelon,

Quindi lo uso per ottenere il mio IP pubblico. :)curl whatismyip.org | grep -A1 'Your IP Address'
shrekuu,

6
Allo stesso modo -B1, -B2, -B3, -A1, -A2, -A3. . .
meawoppl,

5
@shrek curl icanhazip.com (non serve grep necessario) :)
alexyorke

1
La vostra domanda ha risposto alla mia domanda ... -A1. Grazie!
S3DEV,

Risposte:


181

puoi provare con awk:

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

3
Per chiunque volesse davvero un equivalente grep -A2 (che è quello di cui avevo bisogno), getline mangia solo la linea e passa alla successiva. Quindi quello che ha funzionato per me è stato letteralmente soloawk '/blah/{getline; getline; print}' logfile
Aaron R.

160

se vuoi restare su grep:

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

o

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

2
@Kent, grazie per il suggerimento. Dal mio POV, grep è molto più leggibile e facile da comprendere rispetto a sed o alla risposta awk contrassegnata come migliore risposta .... ma sono solo io forse :)
icasimpan,

2
Per coloro che sono curiosi di sapere cosa fa -v: -v --invert-match Inverte il senso della corrispondenza, per selezionare linee non corrispondenti. (-v è specificato da POSIX.)
Sammi

2
Mi piace molto questa risposta, ma non funzionerà se hai due righe di fila contenenti "blah" e vuoi ottenere la seconda (perché è "la riga successiva dopo quella abbinata"). Non riesco a pensare a nessun caso d'uso per quello dalla parte superiore della mia testa, ma vale la pena notare.
Stregone di stagno

La soluzione migliore è semplicemente "ok". Se anche la seconda riga contiene "blah", avrai un vero casino tra le mani.
riwalk

32

Piping è tuo amico ...

Usa grep -A1per mostrare la riga successiva dopo una partita, quindi convoglia il risultato taile prendi solo 1 riga,

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

1
Se "term" si trova sull'ultima riga, questo restituirà la riga contenente "term" invece di niente, cosa vorresti.
Anonimo

tail -n 1 risulterà solo sull'ultima riga dell'intero file
Sebastian,

13

Ottima risposta da Raim, è stato molto utile per me. È banale estenderlo per stampare, ad esempio, la linea 7 dopo il motivo

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

9

Se le righe successive non contengono mai "blah", puoi filtrarle con:

grep -A1 blah logfile | grep -v blah

L'uso di cat logfile | ...non è necessario.


5

In generale, sono d'accordo che stai chiedendo molto grep qui e che un altro strumento potrebbe essere la soluzione migliore. Ma in un ambiente incorporato, potrei non volere sedo awksemplicemente fare questo. Ho trovato che la seguente soluzione funziona (purché non corrispondano in modo contiguo):

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

Fondamentalmente, abbinali, aggiungendo 1 riga di contesto per ogni corrispondenza, quindi esegui il pipe attraverso una corrispondenza inversa del modello originale per eliminarli. Questo ovviamente significa che puoi presumere che il tuo modello non sia visibile nella riga "successiva".


5

Finora sono state fornite molte buone risposte a questa domanda, ma ne manco ancora una awksenza utilizzarla getline. Poiché, in generale , non è necessario utilizzare getline, sceglierei:

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

o

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

La logica consiste sempre nel memorizzare la riga in cui si trova "blah" e quindi stampare quelle righe che sono una riga dopo.

Test

File di esempio:

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

Ottieni tutte le righe dopo "blah". Questo stampa un altro "blah" se appare dopo il primo.

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

Ottieni tutte le righe dopo "blah" se non contengono "blah".

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

5

Non conosco alcun modo per farlo con grep, ma è possibile usare awk per ottenere lo stesso risultato:

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

@jww Non c'è differenza. Come puoi vedere dai timestamp che distano solo pochi minuti, sembra che io abbia risposto più o meno allo stesso tempo.
raimue

4

avviso perl-one-liner

solo per divertimento ... stampa solo una riga dopo la partita

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

ancora più divertente ... stampa le prossime dieci righe dopo la partita

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

un po 'barare, dato che in realtà ci sono due comandi


Puoi spiegare $. == $ next? Chiaramente è più di un confronto numerico del numero di riga corrente con $ next, ma non capisco come / perché funzioni.
Keith Bentrup,

Non è altro. $. == $next && printè lo stesso diprint if $. == $next
beasy,

Ah, vedo adesso. Grazie! Delle 2 parti, ognuna è vera ed esegue su iterazioni adiacenti separate del loop. Suppongo che il punto fosse stampare una riga dopo ogni corrispondenza che si desidera invertire l'ordine (si comporterebbe più come grep -A1). Se si desidera stampare solo le righe successive ma mai una riga con una corrispondenza, è necessario mantenerla in questo ordine. (notando solo come $ prossimo verrebbe bloccato per le partite consecutive)
Keith Bentrup

3

Sembra che tu stia usando lo strumento sbagliato lì. Grep non è così sofisticato, penso che tu voglia intensificare il awk come strumento per il lavoro:

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

Se hai qualche problema fammi sapere, penso che valga la pena imparare un po 'di imbarazzo, è un ottimo strumento :)

ps Questo esempio non vince un "uso inutile del premio gatto";) http://porkmail.org/era/unix/award.html


3
A proposito, puoi saltare "$ 0" in stampa.
Michał Šrajer,

0

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

Coda prima 2 e poi testa l'ultima per ottenere esattamente la prima riga dopo l'incontro.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.