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

273
grep -A1 'blah' logfile

感谢这个命令,对于每一行中包含“blah”的日志文件,我都得到了包含“blah”和其后一行的输出。虽然很简单,但我找不到一种方法来省略包含“blah”的那一行,并且仅仅在输出中显示下一行。


96
我认为很多人会来到这里寻找“-A1”选项。 - mirelon
然后我使用这个命令获取我的公网IP地址。 :) curl whatismyip.org | grep -A1 'Your IP Address' - shrekuu
8
同样地,-B1、-B2、-B3、-A1、-A2、-A3…… - meawoppl
7
@shrek curl http://icanhazip.com(无需grep) :) - alexyorke
3
你的问题回答了我的问题...-A1。谢谢! - S3DEV
警告:许多解决方案假定1 /文件中只有一个匹配项,或2 /匹配行被很好地分隔(不相邻)。 - anthony
14个回答

215

你可以尝试使用awk:

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

7
对于那些真正需要grep -A2等效命令(这也是我所需的),getline只会读取该行并继续下一行。因此,对我有效的方法就是 awk '/blah/{getline; getline; print}' logfile - Aaron R.
1
我喜欢这个getline解决方案。 - Supertech
3
警告:假设您不会连续获得两行匹配的文本。 - anthony
而且文档的最后一行不匹配。 - Sandra

208

如果你想坚持使用grep:

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

或者可以使用sed:

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

3
@Kent,感谢你的提示。但就我个人而言,与被标记为最佳答案的sed或awk答案相比,grep更易读且更易理解...也许只是我的看法 :) - icasimpan
4
对于那些想知道“-v”是什么意思的人: -v --invert-match 反转匹配的含义,选择不匹配的行。(POSIX 规范中指定了“-v”。) - Sámal Rasmussen
3
我很喜欢这个答案,但是如果你有两行连续包含“blah”,并且想要获取第二行(因为它是“匹配行之后的下一行”),那么它将无法起作用。我目前无法想到任何用例,但值得注意。 - Tin Wizard
最佳解决方案只是“还行”。如果第二行也有“blah”,那么你会遇到真正的麻烦。 - riwalk
1
警告:假设您不会在相邻的两行中获得两个匹配的行。 "grep" 将会有额外的 "--" 行,而 "sed" 则跳过这些行。但是,当不是这种情况时,我发现这个 "sed" 解决方案最有用。 - anthony
“sed”选项对于许多用例非常有用。 - glwhart

39

管道是你的好伙伴...

使用grep -A1命令显示匹配行的下一行,然后将结果传输到tail并且只获取一行。

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

1
如果“term”在最后一行,它将返回包含“term”的行,而不是空白,这正是您想要的。 - Onnonymous
4
tail -n 1只会返回整个文件的最后一行。 - Sebastian

14

raim的回答非常好,对我很有用。将其扩展以在模式后打印第7行等内容非常简单。

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

13

迄今为止,已经有很多好的答案给出了这个问题,但是我仍然想要一个不使用 getlineawk 答案。因为,通常情况下,不必使用 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

1
这是一个很好的解决方案,可以处理连续匹配行的两种可能方式...完整性得到了赞同! - anthony

12

如果下一行没有包含“blah”,您可以使用以下方式过滤它们:

grep -A1 blah logfile | grep -v blah

不需要使用cat logfile | ...


如果您不喜欢“cat”,但想要在复杂的管道开始处使用文件名,请尝试以下命令:<logfile grep -A1 blah | grep -v blah。这是完全有效的BASH命令! - anthony

7

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

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

@jww 没有区别。正如您可以看到时间戳几乎相隔几分钟,似乎我在同一时间回答了问题。 - raimue

6

总的来说,我同意这里对grep的要求很高,另外一种工具可能更好。但是在嵌入式环境中,我可能不想使用sed或awk来完成这个任务。我发现以下解决方案可以解决问题(只要它们不是连续匹配):

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

基本上,匹配它们,并在每次匹配时附加1行上下文,然后将其通过原始模式的反向匹配进行管道传输以剥离它们。当然,这意味着您可以假设您的模式不会出现在“下一”行中。

警告:它还会在多个匹配项上输出“--”分隔符。 - anthony

4

Perl一行代码告警

只是为了好玩...在匹配后只打印一行

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

更有趣的是...在匹配后打印接下来的十行。
perl -lne 'push @nexts, (($.+1)..($.+10)) if /match/; $. ~~ @nexts && print' data.txt

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


你能解释一下 $.==$next 吗?显然它不仅仅是当前行号与 $next 的数字比较,但我不明白它是如何和为什么起作用的。 - Keith Bentrup
这只是这样而已。$. == $next && printprint if $. == $next是相同的。 - beasy
啊,我现在明白了。谢谢!这两个部分中,每个部分都是真实的,并且在循环的不同、相邻迭代中执行。我想如果目的是在任何匹配后打印任何行,您可能希望反转顺序(更像 grep -A1)。如果您只想打印下一行,但从不与匹配行一起打印,则应保留此顺序。(只是注意连续匹配会如何破坏 $next) - Keith Bentrup

3
看起来你使用的工具不太对。grep并不是那么复杂,我认为你需要升级到awk作为该任务的工具: awk '/blah/ { getline; print $0 }' logfile 如果出现任何问题,请告诉我,我认为学习一些awk非常值得,它是一个很棒的工具 :)
附:这个例子不会赢得“使用less use of cat award”的奖项 ;) http://porkmail.org/era/unix/award.html

4
顺便提一下,在打印时可以省略 "$0"。 - Michał Šrajer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接