使用 sed 查找文件中的所有匹配项

使用 sed 查找文件中的所有匹配项

使用 OPEN STEP 4.2 操作系统...我当前正在使用以下sed命令:

sed -n '1,/141.299.99.1/p' TESTFILE | tail -3

此命令将在 IP 为 141.299.99.1 的文件中查找一个实例,并且还包含其前面的 3 行,这一切都很好,但我还想查找该 IP 的所有实例及其前面的 3 行而且不仅仅是第一个。

答案1

grep会在这方面做得更好:

grep -B 3 141.299.99.1 TESTFILE

-B 3方法在每场比赛之前打印三行。这将--在每组行之间打印。要禁用它,--no-group-separator也请使用。

-B选项支持GNUgrep以及大多数 BSD 版本(操作系统X,自由BSD,开放BSD,网络BSD),但从技术上讲它不是标准选项。

答案2

有了sed它就可以做滑动窗了。

sed '1N;$!N;/141.299.99.1/P;D'

就可以了。但要小心 -bash疯狂的扩张行为! 即使被引用!从命令历史记录中输入命令字符串可能会让它变得有点疯狂。命令前缀为set +H;如果您发现这种情况,。然后重新启用它(但为什么???)之后再做set -H

当然,这仅适用于您使用bash- 虽然我不相信你是。我是相当确定你正在与csh-(这恰好是 shell 的疯狂行为bash模仿了历史扩展,但可能没有达到 c shell 所采取的极端)。所以大概应该\!有效。我希望。

这都是可移植的代码:POSIX 描述它的三个运算符如下:(尽管值得注意的是,我只是在 2001 年才确认了这个描述的存在)

[2addr]N 将下一行输入(减去其终止\newline)附加到模式空间,使用嵌入的\newline 将附加材料与原始材料分开。请注意,当前行号发生变化。

[2addr]P 将模式空间(直到第一个\n行)写入标准输出。

[2addr]D 通过第一个 ewline 删除模式空间的初始段\n并开始下一个循环。

因此,在第一行中,您向模式空间添加了一条额外的行,因此它看起来像这样:

^line 1s contents\nline 2s contents$

然后在第一行和此后的每一行 - 除了最后一行 - 你添加其他线到图案空间。所以它看起来像这样:

^line 1\nline 2\nline 3$

如果你的 IP 地址被发现,你P会打印到第一个换行符,所以这里只显示第 1 行。在每个周期结束时,您D都会选择相同的内容并从剩余的内容开始。所以下一个周期看起来像:

^line 2\nline 3\nline 4$

...等等。如果您的 IP 地址在这三个地址中的任何一个上找到,则每次都会打印出最旧的 IP 地址。所以你总是仅有的前面三行。

这是一个简单的例子。我将为每个以零结尾的数字打印一个三行缓冲区:

seq 10 52 | sed '1N;$!N;/0\(\n\|$\)/P;D'

10
18
19
20
28
29
30
38
39
40
48
49
50

这个比你的情况复杂一点,因为我必须从0\n换行符或0$模式空间末尾交替以更接近你的问题 - 但它们有微妙的不同,因为这需要一个锚 - 这可能有点困难,因为模式空间不断变化。

我使用 10 和 52 的奇怪情况来表明,只要锚点是灵活的,那么输出也是灵活的。完全可移植,我可以通过依靠算法来实现相同的结果并执行以下操作:

seq 10 52 | sed '1N;$!N;/[90]\n/P;D'

并扩大搜索范围,同时限制我的窗口 - 从 0 到 9 和 0,从 3 行到两行。

无论如何,你明白了。

答案3

这是使用 sed 移动窗口进行模拟的尝试grep -B3,基于这个 GNU sed 示例(但希望符合 POSIX 标准 - 感谢@StéphaneChazelas):

sed -e '1h;2,4{;H;g;}' -e '1,3d' -e '/141\.299\.99\.1/P' -e '$!N;D' file

前两个表达式启动多行模式缓冲区,并允许其处理第一个匹配之前的前置上下文少于 3 行的边缘情况。中间(正则表达式匹配)表达式从窗口顶部打印一行,直到所需的匹配文本通过模式缓冲区向上传递。最后一个$!N;D将窗口滚动一行,除非到达输入末尾。

答案4

当可用时,您可以使用pcregrep:

pcregrep -M '.*\n.*\n.*\n141.299.99.1' file

相关内容