如何只显示匹配的行之后的下一行?


218
grep -A1 'blah' logfile

多亏了此命令,每行中都有'blah'的行,我得到了包含'blah'的行以及日志文件中下一行的输出。这可能很简单,但是我找不到一种方法来省略具有“ blah”的行,而在输出中显示下一行。


71
我认为会有很多人来这里寻求-A1选择
mirelon 2014年

然后,我用它来获取我的公共IP。:)curl whatismyip.org | grep -A1 'Your IP Address'
shrekuu

6
类似地-B1,-B2,-B3,-A1,-A2,-A3。。。
meawoppl

5
@shrek curl icanhazip.com(无需grep):)
alexyorke

1
您的问题回答了我的问题-A1。谢谢!
S3DEV

Answers:


181

您可以尝试使用awk:

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

3
对于真正想要grep -A2等效项的人(这是我所需要的),getline会吃掉该行,然后继续执行下一个。所以实际上对我有用的是awk '/blah/{getline; getline; print}' logfile
Aaron R.

160

如果您想坚持使用grep:

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

要么

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

2
@肯特,谢谢你的提示。从我的观点来看,与sed或标记为最佳答案的awk答案相比,grep更具可读性和易掌握性....但这可能只是我自己:)
icasimpan 2014年

2
对于那些对-v的功能感到好奇的人:-v --invert-match反转匹配的含义,以选择不匹配的行。(-v由POSIX指定。)
Sammi'2

2
我真的很喜欢这个答案,但是如果您连续有两行包含“ blah”并且想要获取第二行(因为它是“匹配的行之后的下一行”),它将无法正常工作。我想不出什么用例,但是值得注意。
锡巫师

最佳解决方案只是“确定”。如果第二行碰巧也带有“ blah”,那么您的手上将一团糟。
riwalk19年

32

管道是你的朋友...

使用grep -A1匹配后显示的下一行,然后通过管道将结果tail,只抢到1号线,

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

1
如果“ term”在最后一行,则将返回包含“ term”的行,而不是您想要的内容。
匿名

tail -n 1将仅导致整个文件的最后一行
Sebastian

13

raim的很好回答,对我来说非常有用。扩展它以打印例如图案后的第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

总的来说,我同意您在这里要问很多grep,并且另一个工具可能是更好的解决方案。但是在嵌入式环境中,我可能不想拥有sedawk仅仅这样做。我发现以下解决方案有效(只要它们不是连续的匹配项):

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"

逻辑总是在于存储找到“ blah”的行,然后打印后一行的那些行。

测试

样本文件:

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

获取“ blah”之后的所有行。如果出现在第一个“ blah”之后,它将打印另一个“ blah”。

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

如果“ blah”之后的所有行本身都不包含“ blah”,则获取它们。

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

5

我不知道用grep做到这一点的任何方法,但是可以使用awk达到相同的结果:

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

@jww没有区别。从相距仅几分钟的时间戳中可以看到,似乎我在同一时间回答了。
raimue

4

Perl一线警报

只是为了好玩...赛后只打印一行

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

更加有趣...比赛后再打印下十行

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

有点作弊,因为实际上有两个命令


您能解释一下$。== $ next吗?显然,这不仅仅是将当前行号与$ next进行数字比较,但我不知道它是如何/为什么工作的。
基思·本特鲁普

仅此而已。$. == $next && printprint if $. == $next
beasy

啊,我明白了。谢谢!在这两个部分中,每个部分都是正确的,并在循环的相邻相邻迭代中执行。我想如果要点是要在任何匹配项之后打印任何行,那么您将想要颠倒顺序(行为将更像grep -A1)。如果只想打印下一行,而不要打印匹配的行,则可以按此顺序打印。(只是指出在连续比赛中如何破坏$ next)
Keith Bentrup

3

好像您在使用错误的工具。Grep并不是那么复杂,我想您想成为awk的工具:

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

如果您遇到任何问题,请告诉我,我认为值得学习awk,它是一个很好的工具:)

ps此示例不会赢得“猫奖的无用使用”;) http://porkmail.org/era/unix/award.html


3
顺便说一句,您可以跳过打印中的“ $ 0”。
米哈尔Šrajer

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.