如何在 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 也是如此。

现在,如果orangelimebanana 都出现在前三行中,则打印倒数第二行 (l2)、最后一行 (l1) 和当前行$0

现在在我们移动到下一行之前减少每个水果的计数,并保存当前行并按时间顺序向后移动前 2 行。

【讨论】:

以上是关于如何在 N 行中 grep 多个字符串的主要内容,如果未能解决你的问题,请参考以下文章

如何在vim中删除N行中的第一个字符?

多个字符串和模式使用grep

如何在 n 行中获取整数直到 \n

如何SQLite 多个关键字匹配查询

如何使用 Python 3.x 在命令行中执行多个命令

如何在表格视图行中有多个单元格?