使用 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
答案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
将下一行输入(减去其终止\n
ewline)附加到模式空间,使用嵌入的\n
ewline 将附加材料与原始材料分开。请注意,当前行号发生变化。
[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