如何在匹配后仅显示下一行?
Posted
技术标签:
【中文标题】如何在匹配后仅显示下一行?【英文标题】:How to show only next line after the matched one? 【发布时间】:2011-11-19 01:37:45 【问题描述】:grep -A1 'blah' logfile
多亏了这个命令,每行都包含“blah”,我得到了包含“blah”的行的输出以及日志文件中的下一行。这可能是一个简单的方法,但我找不到一种方法来省略具有“blah”的行并且only在输出中显示下一行。
【问题讨论】:
我想很多人会来这里寻找-A1
选项
然后我用它来获取我的公共 IP。 :) curl whatismyip.org | grep -A1 'Your IP Address'
类似地 -B1, -B2, -B3, -A1, -A2, -A3 。 . .
@shrek curl icanhazip.com(不需要 grep):)
您的问题回答了我的问题...-A1
。谢谢!
【参考方案1】:
你可以试试 awk:
awk '/blah/getline; print' logfile
【讨论】:
对于任何真正想要 grep -A2 等效项(这是我需要的)的人,getline 只是吃掉这条线并继续下一条。所以对我有用的只是awk '/blah/getline; getline; print' logfile
我喜欢这个 getline 解决方案。
警告:假设您没有得到两个相邻的匹配行【参考方案2】:
我不知道用 grep 有什么方法可以做到这一点,但是可以使用 awk 来实现相同的结果:
awk '/blah/ getline;print' < logfile
【讨论】:
@jww 没有区别。从相隔几分钟的时间戳可以看出,我似乎在同一时间回答了。【参考方案3】:如果你想坚持使用 grep:
grep -A1 'blah' logfile | grep -v "blah"
或者使用 sed:
sed -n '/blah/n;p;' logfile
【讨论】:
@Kent,感谢您的提示。不过,从我的 POV 来看,与 sed 或标记为最佳答案的 awk 答案相比,grep 更具可读性和易于掌握......但也许只是我个人 :) 对于那些好奇 -v 做什么的人: -v --invert-match 反转匹配的意义,选择不匹配的行。 (-v 由 POSIX 指定。) 我真的很喜欢这个答案,但是如果你连续有两行包含“blah”并且想要获得第二行(因为它是“匹配的下一行”)。我想不出任何用例,但值得注意。 最佳解决方案只是“ok”。如果第二行恰好也有“blah”,那你手上就会一团糟。 警告:假设您没有得到两个相邻的匹配行。然后“grep”会有额外的“--”行,而“sed”会跳过行。但我发现这种“sed”解决方案在不是这种情况下最有用。【参考方案4】:您似乎在这里使用了错误的工具。 Grep 并没有那么复杂,我认为您想加强 awk 作为这项工作的工具:
awk '/blah/ getline; print $0 ' logfile
如果您遇到任何问题,请告诉我,我认为它非常值得学习一点 awk,它是一个很棒的工具 :)
附言这个例子没有赢得“无用的猫奖”;) http://porkmail.org/era/unix/award.html
【讨论】:
顺便说一句,您可以跳过打印中的“$0”。【参考方案5】:如果下一行从不包含“blah”,您可以使用以下命令对其进行过滤:
grep -A1 blah logfile | grep -v blah
不需要使用cat logfile | ...
。
【讨论】:
如果你不喜欢 "cat" 但希望文件名位于复杂管道的开头,试试这个<logfile grep -A1 blah | grep -v blah
这是完全有效的 BASH!【参考方案6】:
管道是你的朋友......
使用grep -A1
显示匹配后的下一行,然后将结果通过管道传输到tail
并且只抓取1 行,
cat logs/info.log | grep "term" -A1 | tail -n 1
【讨论】:
如果“term”在最后一行,这将返回包含“term”的行,而不是什么都没有,这是你想要的。 tail -n 1 只会产生整个文件的最后一行【参考方案7】:来自 raim 的出色回答,对我非常有用。将其扩展到打印是微不足道的,例如模式后的第 7 行
awk -v lines=7 '/blah/ for(i=lines;i;--i)getline; print $0 ' logfile
【讨论】:
【参考方案8】:总的来说,我同意您在这里询问了很多 grep,而另一种工具可能是更好的解决方案。但是在嵌入式环境中,我可能不想让sed
或awk
只是为了做到这一点。我发现以下解决方案有效(只要它们不是连续匹配):
grep -A1 AT\+CSQ wvdial.out | grep -v AT\+CSQ
基本上,匹配它们,为每个匹配附加 1 行上下文,然后通过原始模式的反向匹配将其删除。这当然意味着您可以假设您的模式不会出现在“下一个”行中。
【讨论】:
警告:它还会在多个匹配项上输出“--”分隔符。【参考方案9】:到目前为止,这个问题已经给出了很多很好的答案,但我仍然想念一个awk
没有使用getline
的答案。因为in general,没必要用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”。
$ 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
【讨论】:
这是一个很好的解决方案,可以通过两种可能的方式处理连续匹配的行...赞成完整性!【参考方案10】: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 的数字比较,但我不明白它是如何/为什么工作的。 仅此而已。$. == $next && print
与 print if $. == $next
相同
啊,我明白了。谢谢!在 2 个部分中,每个部分都是正确的,并且在循环的单独、相邻的迭代中执行。我想如果关键是在任何匹配之后打印任何你想要颠倒顺序的行(表现得更像grep -A1
)。如果您只想打印下一行而不是匹配的行,那么您将保持此顺序。 (只是注意 $next 将如何在连续比赛中被破坏)【参考方案11】:
grep /模式/ |尾-n 2 |头 -n 1
前 2 尾,然后前尾后尾,以在匹配后准确地获得第一行。
【讨论】:
【参考方案12】:你可以使用 grep,然后在跳转中取行:grep -A1 'blah' logfile | awk 'NR%3==2'
也可以在匹配后取n行,例如:seq 100 | grep -A3 .2 | awk 'NR%5==4'
15
25
35
45
55
65
75
85
95
解释 -
在这里,我们要 grep 所有 *2 行并在其后取 3 行,即 *5。seq 100 | grep -A3 .2
会给你:
12
13
14
15
--
22
23
24
25
--
...
模数 (NR%5) 中的数字是 grep 添加的行(这里是标志 -A3 的 3 行),+2 额外行,因为您有当前匹配行以及 grep 正在添加的 -- 行。
【讨论】:
以上是关于如何在匹配后仅显示下一行?的主要内容,如果未能解决你的问题,请参考以下文章