如何在 N 行中 grep 多个字符串
Posted
技术标签:
【中文标题】如何在 N 行中 grep 多个字符串【英文标题】:How to grep multiples strings within N lines 【发布时间】:2017-01-21 06:12:26 【问题描述】:我想知道我是否可以通过 grep(或任何其他命令)搜索 N 行中的多个字符串。
示例
在 3 行内搜索“orange”、“lime”、“banana”
如果输入文件是
xxx
a lime
b orange
c banana
yyy
d lime
foo
e orange
f banana
我想打印以 a、b、c 开头的三行。 带有搜索字符串的行可以按任意顺序出现。
我不想打印 d、e、f 行,因为中间有一行,所以这三个字符串没有组合在一起。
【问题讨论】:
我随时为您的问题提出修改建议。它是否使您的问题更清楚?对于未来,请提供清晰的示例输入并使用可用的格式选项。 每个字符串都必须匹配一次吗?还是包含banana
的连续三行也匹配成功?
How to find patterns across multiple lines using grep?的可能重复
嗨@MartinNyolt 感谢您编辑它。每个字符串都应该匹配一次,例如:xxx 香蕉香蕉香蕉不是匹配但:xxx abanana,orange,lime。和 yyy 香蕉 b 橙,酸橙是匹配的。
@KrzysztofKaszkowiak 谢谢你的建议,但这不是我想要的
【参考方案1】:
你的问题不太清楚。这是一个简单的 Awk 脚本,它收集连续匹配的行并在数组长于三个元素时打印。
awk '/orange|lime|banana/ a[++n] = $0; next
if (n>=3) for (i=1; i<=n; i++) print a[i]; delete a; n=0
END if (n>=3) for (i=1; i<=n; i++) print a[i] ' file
不清楚您是否要求所有表达式都匹配;这个没有尝试。如果你看到三个连续的带有orange
的行,那就是匹配,将被打印出来。
逻辑应该很简单。数组a
收集匹配项,n
对其进行索引。当我们看到不匹配时,我们检查它的长度,如果它是 3 或更多则打印,然后从一个空数组和索引重新开始。这也(笨拙地)在文件末尾重复,以防文件以匹配结尾。
如果你想允许间隙(所以,如果有三行连续的一行匹配“orange”和“banana”,然后一个不匹配,然后一个匹配“lime”,打印这三行?您的问题不清楚)您可以更改为始终保留最后三行的数组,但是您还需要指定如何处理例如符合这些规则的五行序列。
【讨论】:
【参考方案2】:与 Tripleee 的回答类似,我也会为此目的使用 awk。 主要思想是实现一个简单的状态机。
简单示例
作为一个简单的例子,首先尝试找到三个连续的香蕉行。 考虑模式-动作语句
/banana/ bananas++
对于与正则表达式 banana
匹配的每一行,它都会增加变量 bananas
(在 awk 中,所有变量都初始化为 0)。
当然,你希望bananas
在有不匹配的行时被重置为0,所以你的搜索从头开始:
/banana/ bananas++; next
bananas = 0
您还可以在动作模式中测试变量的值。
例如,如果您想在包含banana
的三行之后打印“Found”,则扩展规则:
/banana/
bananas++
if (bananas >= 3)
print "Found"
bananas = 0
next
这会将变量 bananas
重置为 0,并打印字符串“Found”。
如何继续
使用这个基本思想,您应该能够编写自己的 awk 脚本来处理所有情况。 首先,您应该熟悉 awk(模式、动作、程序执行)。
然后,扩展和调整我的示例以满足您的需求。
特别是,您可能需要一个关联数组matched
,索引为“banana”、“orange”、“lime”。
当当前行匹配/banana/
时设置matched["banana"] = $0
。这会保存当前行以供以后输出。
当当前行与您的任何表达式都不匹配时,您清除整个数组。
找到所有字符串后(matched[s]
不是每个字符串都为空s
),就可以打印matched[s]
的内容了。
我把实际的实现留给你。 正如其他人所说,您的描述使许多极端情况不清楚。 您应该自己弄清楚它们并相应地调整您的实现。
【讨论】:
【参考方案3】:我想你想要这个:
awk '
/banana/ banana=3
/lime/ lime=3
/orange/ orange=3
(orange>0)&&(lime>0)&&(banana>0)print l2,l1,$0
orange--;lime--;banana--;l2=l1;l1=$0' OFS='\n' yourFile
因此,如果您看到单词banana
,则设置banana=3
,因此它对接下来的3 行有效。同样,如果你看到 lime
,给它 3 行机会组成一个小组,orange
也是如此。
现在,如果orange
、lime
和 banana
都出现在前三行中,则打印倒数第二行 (l2
)、最后一行 (l1
) 和当前行$0
。
现在在我们移动到下一行之前减少每个水果的计数,并保存当前行并按时间顺序向后移动前 2 行。
【讨论】:
以上是关于如何在 N 行中 grep 多个字符串的主要内容,如果未能解决你的问题,请参考以下文章