【问题标题】:How to grep multiples strings within N lines如何在 N 行中 grep 多个字符串
【发布时间】:2023-03-09 23:49:02
【问题描述】:

我想知道我是否可以通过 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 的连续三行也匹配成功?
  • 嗨@MartinNyolt 感谢您编辑它。每个字符串都应该匹配一次,例如:xxx 香蕉香蕉香蕉不是匹配但:xxx abanana,orange,lime。和 yyy 香蕉 b 橙,酸橙是匹配的。
  • @KrzysztofKaszkowiak 谢谢你的建议,但这不是我想要的

标签: linux shell command-line grep gawk


【解决方案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 行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多