![打印找到的行之前/之后的 X 行](https://linux22.com/image/1389610/%E6%89%93%E5%8D%B0%E6%89%BE%E5%88%B0%E7%9A%84%E8%A1%8C%E4%B9%8B%E5%89%8D%2F%E4%B9%8B%E5%90%8E%E7%9A%84%20X%20%E8%A1%8C.png)
我想在某个文件中搜索特定的字符串。如果找到了该字符串,我还想打印该行之前(或之后)的 X 行。
可以用 grep 或 awk 来做吗,或者我需要组合使用吗?
我想要类似的东西这,但不是所有命中之前或之后的尾随/前导线,只有 X 条。
例如,如果我的输入如下所示:
line1 with a pattern
line2
line3
line4 with a pattern
line5
line6
line7 with a pattern
...
例如,我想搜索单词“pattern”,并输出该行 + 其后两行的行,但不输出紧跟该模式行的行。因此,所需的输出是:
line1 with a pattern
line3
line4 with a pattern
line6
line7 with a pattern
...
答案1
grep
将为您完成此操作,使用选项-A
(after) 和-B
(before) 以及-C
(context)。我经常使用的一个例子是:
sudo lspci -vnn | grep -i net -A 12
因为这个命令匹配后会显示12行,其中包括用于控制网络(-i net)卡的驱动程序。一般来说,命令是:
grep text_to_search -A n -B m file.extension
这将输出m
匹配之前的行和n
匹配之后的行。或者你可以使用
grep text_to_search -C n file.extension
显示n
找到的文本周围的总行数(匹配前一半,匹配后一半)。
答案2
在仔细研究了这个问题之后,我觉得我必须修改一下关于使用标准 GNU 工具而不使用脚本的可行性的评论。这可能是非常由于特殊情况,很难做到。
如果您不介意使用 awk,我可以提供以下解决方案。这个脚本context.awk
仍然相当简洁:
{
lines[NR] = $0
if (dump[NR]) {
print $0;
if ($0 ~ Pattern) {
if (NR-Delta in lines) {
print "---"
print lines[NR-Delta]
}
dump[NR+Delta] = 1
print $0;
}
if (NR-Delta in lines)
delete lines [NR-Delta];
}
必须按如下方式调用它:
awk -v Delta=X -v Pattern=PATTERN -f context.awk sample.txt
其中X
是所需的“上下文距离”,PATTERN
搜索模式为。脚本尝试通过在---
中间打印行来分隔文件中的多个模式上下文。因此,例如,以下sample.txt
line1
line2
line3 XXX
line4
line5
line6
line7 XXX
line8
line9
line10 XXX
line11
使用此调用
awk -v Delta=3 -v Pattern=XXX -f context.awk sample.txt
将产生以下输出
line3 XXX
line6
---
line4
line7 XXX
line10 XXX
---
line7 XXX
line10 XXX
答案3
以下sed
命令似乎适用于您描述的情况,我将重述为:打印与我的模式匹配的行,不打印紧接着的下一行,还打印我的模式后两行的行,然后继续搜索模式匹配。
sed -n -e '/with a pattern/ {h;n;n;H;x;p}' file
它看起来有点丑,但通过添加额外的n
(跳过行,移动到下一行)和H
(通过将其附加到保持缓冲区来保留这一行)命令,您可以根据模式匹配构建任意的保持/跳过关系。
请注意,在匹配之后,我们首先使用 命令将匹配的行复制到保持缓冲区h
。最后,我们用 交换保持和模式空间,x
并使用 打印模式空间p
。此时sed
将继续逐行处理文件以寻找另一个匹配项。
sed
可以找到命令的便捷参考这里。
答案4
grep -A2 <pattern> file | grep -B1 <pattern> | grep -v "\-\-"
对我有用:
user@box /tmp $ grep -A2 "with a pattern" test.txt | grep -B1 "with a pattern" | grep -v "\-\-"
line1 with a pattern
line3
line4 with a pattern
line6
line7 with a pattern
user@box /tmp $ cat test.txt
line1 with a pattern
line2
line3
line4 with a pattern
line5
line6
line7 with a pattern