仅返回匹配模式后的行的一部分


109

因此,当我使用要处理的特定日志集时,仅cat使用拉开文件然后使用grep来获取匹配行就可以了。它需要一种将线与模式匹配的方法,但只需要在匹配后返回该线的一部分。比赛之前和之后的部分将不断变化。我使用过sedawk,但无法弄清楚如何过滤线以删除比赛之前的部分,或者仅在比赛之后返回部分,这两种方法都可以使用。这是我需要过滤的一行示例:

2011-11-07T05:37:43-08:00 <0.4> isi-udb5-ash4-1(id1) /boot/kernel.amd64/kernel: [gmp_info.c:1758](pid 40370="kt: gmp-drive-updat")(tid=100872) new group: <15,1773>: { 1:0-25,27-34,37-38, 2:0-33,35-36, 3:0-35, 4:0-9,11-14,16-32,34-38, 5:0-35, 6:0-15,17-36, 7:0-16,18-36, 8:0-14,16-32,34-36, 9:0-10,12-36, 10-11:0-35, 12:0-5,7-30,32-35, 13-19:0-35, 20:0,2-35, down: 8:15, soft_failed: 1:27, 8:15, stalled: 12:6,31, 20:1 }

我需要的部分是“停顿”之后的所有内容。

其背后的背景是,我可以找出停顿的频率:

cat messages | grep stalled | wc -l

我需要做的是找出某个节点已停顿了多少次(由“停顿”后每个冒号之前的部分指示。如果我只是为此而grep(即20 :),它可能会返回软失败的行,但是我只需要过滤停顿的部分,这样我就可以从停顿的那些节点中为特定节点进行grep。

出于所有目的和目的,这是一个具有标准GNU核心utils的freebsd系统,但是我无法安装任何额外的辅助工具。


@Gilles,奇怪,当我搜索时,它怎么没有弹出,尽管我没有使用我最终使用的标题...但是它没有显示在标题下方的屏幕上。无论如何,尽管我需要比赛后的整行,而不是第一个字,但这可能会使我进入想要的位置,但是可能不需要太多改变。
MaQleod 2011年

它的头衔糟透了。我偷了你的,很好。采取sed解决方案,不要特别对待空格。
吉尔斯

@Gilles,我不太确定该怎么做。我仍在学习sed。
MaQleod


1
@ shaa0601我不明白您的问题,要在没有格式的情况下添加注释特别困难。提出一个新的,独立的问题。
吉尔斯2014年

Answers:


141

规范的工具是sed

sed -n -e 's/^.*stalled: //p'

详细说明:

  • -n 表示默认情况下不打印任何内容。
  • -e 后面是sed命令。
  • s 是模式替换命令。
  • 正则表达式^.*stalled:与您要查找的模式相匹配,再加上任何前面的文本(.*表示任何文本,并带有首字母^,表示匹配从行的开头开始)。请注意,如果在线上stalled:发生多次,则它将与最后一次匹配。
  • 匹配项(即直到的行中的所有内容)stalled:都由空字符串(即已删除)替换。
  • 最终p手段是打印转换后的行。

如果要保留匹配部分,请使用向后引用:\1替换部分中的内容指定\(…\)模式中组内的内容。在这里,您可以stalled:在替换部分再次写;当您要查找的模式比简单字符串更笼统时,此功能很有用。

sed -n -e 's/^.*\(stalled: \)/\1/p'

有时,您需要在比赛之后删除该行的一部分。您可以通过将其包括.*$在模式末尾(任何文本.*后跟该行的末尾$)来将其包括在匹配项中。除非将该零件放在替换文本中引用的组中,否则行的结尾将不在输出中。

作为组和反向引用的进一步说明,此命令交换匹配之前的部分和匹配之后的部分。

sed -n -e 's/^\(.*\)\(stalled: \)\(.*\)$/\3\2\1/p'

我已经尝试了前两个示例,但似乎挂起了。我没有收到错误消息,也没有得到新的提示,什么也没有。
2011年

2
@MaQleod哦,它正在等待标准输入的输入,这是终端,因为您尚未重定向它。在这里,您将要进行输入重定向sed … <messages,因为您要处理文件中的数据。要对另一个命令产生的数据进行处理,可以使用管道:somecommand | sed …
吉尔斯

1
对,当天停电了。命令工作完美,谢谢。
MaQleod

1
到目前为止,我所见过的关于sed的最佳解释-谢谢!
乔恩·沃兹沃思

1
@ungalcrys的短版是什么?这不等同于我的答案中的任何命令。我建议您编写它,sed 's/^.*stalled//'因为-r它特定于Linux,并且不能在其他系统(例如macOS)上运行,在这里您不会从中受益。
吉尔斯

72

您已经使用的其他规范工具grep

例如:

grep -o 'stalled.*'

与Gilles的第二个选项具有相同的结果:

sed -n -e 's/^.*\(stalled: \)/\1/p'

-o标志返回--only-matching表达式的一部分,而不是整个行(当然,通常由grep完成)。

要从输出中删除“ stalled:”,我们可以使用第三个标准工具,剪切:

grep -o 'stalled.*' | cut -f2- -d:

cut命令使用定界符:并将字段2打印到最后。当然,这是一个偏好问题,但是cut我发现语法很容易记住。


1
感谢您提及该-o选项!我想指出的是,该行grep不能识别\n为换行符,因此您的第一个示例仅与第一个n字符匹配。例如,echo "Hello Anne" | grep -o 'A[^\n]*'返回字符串A。但是,由于匹配换行符以外的任何字符,所以echo "Hello Anne" | grep -o 'A.*'返回期望的。Anne.
adamlamar

1
请注意,@ poige删除了cut定界符周围的引号-d':'。我发现用引号(例如-d' '或)更容易记住-d';'
安妮·范·罗苏姆

根据您的发现,使用引号也应该更容易记住-f 2。说真的,为什么不呢?
poige

因为如果不加引号,则分号(例如分号);而不是冒号:将被不同地解释。当然,这是合乎逻辑的行为,但我仍然喜欢依靠肌肉记忆。我不想一次引用分隔符,而另一次不引用。就像我之前说的那样,只是个人喜好:更容易记住。
安妮·范·罗瑟姆

这个时期的一部分.*对我来说非常有效: cat filename | grep 'Return only this line xyz text' | grep -o 'xyz.*' 回报xyz text
罗恩(Ron)2007年

4

ifconfig | grep eth0 | cut -f3- -d:以前拿这个

    [root@MyPC ~]# ifconfig
    eth0  Link encap:Ethernet  HWaddr AC:B4:CA:DD:E6:F8
          inet addr:192.168.0.2  Bcast:192.168.0.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:78998810244 errors:1 dropped:0 overruns:0 frame:1
          TX packets:20113430261 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:110947036025418 (100.9 TiB)  TX bytes:15010653222322 (13.6 TiB)

并使其看起来像这样

    [root@MyPC ~]# ifconfig | grep eth0 | cut -f3- -d:
    C4:7A:4D:F6:B8

2
这会回答问题吗?
斯蒂芬·劳奇

1
您可以使用cat /sys/class/net/*/address,无需解析。
安妮·范·罗苏姆

1

您考虑的另一种规范工具awk可以与以下行一起使用:

awk -F"stalled" '/stalled/{print $2}' messages

详细说明:

  • -F为该行定义一个分隔符,即“停滞”。分隔符之前的$1所有内容均以寻址,之后的所有内容均以寻址$2
  • /reg-ex/ 搜索匹配的正则表达式,在这种情况下为“ stalled”。
  • {print $<n>}-打印n列。由于分隔符定义为停顿,因此停顿后的所有内容均视为第二列。
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.