Como mostrar apenas a próxima linha após a correspondência?

218
grep -A1 'blah' logfile

Graças a esse comando para cada linha que contém 'blá', recebo a saída da linha que contém 'blá' e a próxima linha que segue no arquivo de log. Pode ser simples, mas não consigo encontrar uma maneira de omitir a linha que tem 'blá' e mostrar apenas a próxima linha na saída.

facha
fonte
71
Eu acho que muitas pessoas virão aqui procurando a -A1opção
mirelon
Então eu uso isso para obter meu IP público. :)curl whatismyip.org | grep -A1 'Your IP Address'
shrekuu
6
Da mesma forma -B1, -B2, -B3, -A1, -A2, -A3. . .
meawoppl
5
@shrek onda icanhazip.com (sem grep necessário) :)
alexyorke
1
Sua pergunta respondeu à minha pergunta ... -A1. Obrigado!
S3DEV 25/09/19

Respostas:

181

você pode tentar com o awk:

awk '/blah/{getline; print}' logfile
Michał Šrajer
fonte
3
Para quem realmente queria um equivalente grep -A2 (que é o que eu precisava), o getline apenas come a linha e passa para a próxima. Então, o que funcionou para mim foi literalmente apenasawk '/blah/{getline; getline; print}' logfile
Aaron R.
160

se você deseja manter o grep:

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

ou

sed -n '/blah/{n;p;}' logfile
Kent
fonte
2
@ Kent, obrigado pela dica. Do meu POV, porém, grep é muito mais legível e fácil de entender em relação ao sed ou a resposta awk marcada como melhor resposta .... mas é só me maybe :)
icasimpan
2
Para aqueles curiosos sobre o que -v faz: -v --invert-match Inverta o senso de correspondência, para selecionar linhas não correspondentes. (-v é especificado por POSIX.)
Sammi 08/02
2
Eu realmente gosto dessa resposta, mas não funcionará se você tiver duas linhas seguidas contendo "blá" e quiser obter a segunda (porque é "a próxima linha após a correspondência"). Não consigo pensar em nenhum caso de uso disso, mas vale a pena notar.
Assistente de lata
A solução superior é apenas "ok". Se a segunda linha também tiver "blá", você terá uma verdadeira bagunça nas mãos.
riwalk
32

Piping é seu amigo ...

Use grep -A1para mostrar a próxima linha após uma partida e, em seguida, canalize o resultado taile pegue apenas 1 linha,

cat logs/info.log | grep "term" -A1 | tail -n 1
weisjohn
fonte
1
Se "termo" estiver na última linha, isso retornará a linha que contém "termo" em vez de nada, o que você deseja.
Onnonymous
tail -n 1 resultará apenas na última linha do arquivo inteiro
Sebastian
13

Ótima resposta do raim, foi muito útil para mim. É trivial estender isso para imprimir, por exemplo, a linha 7 após o padrão

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

Se as próximas linhas nunca contiverem 'blá', você poderá filtrá-las com:

grep -A1 blah logfile | grep -v blah

O uso de cat logfile | ...não é necessário.

ott--
fonte
5

Em geral, concordo que você esteja solicitando muito grep aqui e que outra ferramenta pode ser a melhor solução. Mas em um ambiente incorporado, talvez eu não queira ter sedou awkapenas fazer isso. Descobri que a seguinte solução funciona (desde que não sejam correspondências contíguas):

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

Basicamente, combine-os, acrescentando 1 linha de contexto para cada correspondência e, em seguida, passe-a através de uma correspondência inversa do seu padrão original para removê-las. É claro que isso significa que você pode assumir que seu padrão não aparece na linha "próxima".

Travis Griggs
fonte
5

Muitas boas respostas foram dadas a essa pergunta até agora, mas ainda sinto falta de uma por awknão usar getline. Desde que, em geral , não é necessário usar getline, eu iria para:

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

ou

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

A lógica sempre consiste em armazenar a linha onde "blá" é encontrado e, em seguida, imprimir as linhas que são uma linha depois.

Teste

Arquivo de exemplo:

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

Obter todas as linhas depois de "blá". Isso imprime outro "blá" se aparecer após o primeiro.

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

Obtenha todas as linhas após "blá" se elas não contiverem "blá".

$ awk '/blah/ {f=NR} f && NR==f+1' a
1
4
7
fedorqui 'Então pare de prejudicar'
fonte
5

Não conheço nenhuma maneira de fazer isso com o grep, mas é possível usar o awk para obter o mesmo resultado:

awk '/blah/ {getline;print}' < logfile
raimue
fonte
@jww Não há diferença. Como você pode ver pelos registros de data e hora que estão apenas a alguns minutos, parece que eu respondi na mesma hora.
raimue 22/02
4

alerta one-liner perl

só por diversão ... imprima apenas uma linha após a partida

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

ainda mais divertido ... imprima as próximas dez linhas após a partida

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

meio que trapaceando, já que na verdade existem dois comandos

beasy
fonte
Você pode explicar $. == $ next? Claramente, é mais do que uma comparação numérica do número da linha atual com $ next, mas não entendo como / por que funciona.
Keith Bentrup
Não é mais do que isso. $. == $next && printé o mesmo queprint if $. == $next
beasy 27/03/19
Ah, eu vejo agora. THX! Das 2 partes, cada uma é verdadeira e é executada em iterações adjacentes separadas do loop. Suponho que se o ponto fosse imprimir qualquer linha após qualquer correspondência que você desejasse reverter a ordem (se comportaria mais como grep -A1). Se você deseja imprimir apenas as próximas linhas, mas nunca uma linha com uma correspondência, mantenha-a nessa ordem. (apenas observando como $ next seria derrotado por partidas consecutivas) #
Keith Bentrup 28/03/19
3

Parece que você está usando a ferramenta errada lá. O Grep não é tão sofisticado, acho que você deseja aumentar o awk como a ferramenta para o trabalho:

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

Se você tiver algum problema, avise-me, acho que vale a pena aprender um pouco do awk, é uma ótima ferramenta :)

ps Este exemplo não ganha um 'prêmio de uso inútil de gato';) http://porkmail.org/era/unix/award.html

sillyMunky
fonte
3
BTW, você pode pular "$ 0" na impressão.
Michał Šrajer
0

grep / Padrão / | cauda -n 2 | cabeça -n 1

Cauda primeiro 2 e depois cabeça última para obter exatamente a primeira linha após a partida.

Amrit Pal Singh
fonte