【问题标题】:Match all lines that include StringA but ignore lines that also contain StringB匹配所有包含 StringS 的行,但忽略也包含 String 的行
【发布时间】:2021-03-01 18:52:11
【问题描述】:

我需要匹配文件中的模式并打印以下 2 行。我为此使用 grep -A2 。 但我想忽略第一个 grep 中的一些行。

我需要第一个 'grep -A2' 的输出来做一些进一步的处理,所以据我所知,到 grep -v 的管道对我没有帮助。

$cat file.txt
stringA-hurdygurdy-andmorechars
line1
line2
stringA-hurdygurdy-stringB-andmorechars
line1
line2
stringA-hurdygurdy-andmorechars
line1
line2

我需要 grep -A2 所有包含“stringA-hurdygurdy”的行,但不是包含 stringB 的行。

我在努力 grep -A2 ^stringA.*[^stringB].* file.txt

【问题讨论】:

  • Dupes 不正确,因为给定的grep 解决方案不适用于非 gnu awk,因为正在使用 -A2awk 将是比grep 更好的解决方案。
  • 请将该示例输入的所需输出(无描述)添加到您的问题(无评论)。

标签: regex awk grep


【解决方案1】:

您可以使用awk

awk '/stringA/ && !/stringB/ {n = NR+2} n >= NR' file.txt

stringA-hurdygurdy-andmorechars
line1
line2
stringA-hurdygurdy-andmorechars
line1
line2

【讨论】:

    【解决方案2】:

    使用这个 Perl 单线(类似于 anubhava 中的 awk 解决方案):

    perl -lne '$line_num = $. if /stringA/ && !/stringB/; print if $line_num <= $. && $. <= ( $line_num + 2 );' file.txt
    

    输出:

    stringA-hurdygurdy-andmorechars
    line1
    line2
    stringA-hurdygurdy-andmorechars
    line1
    line2
    
    

    Perl 单行代码使用这些命令行标志:
    -e:告诉 Perl 查找内联代码,而不是在文件中。
    -n:循环输入一行一次,默认将其分配给$_
    -l:在执行内联代码之前剥离输入行分隔符(默认为 *NIX 上的"\n"),并在打印时附加它。它在 OP 发布的这种特殊情况下的使用是可选的。

    $. : 当前输入行号。

    另请参阅:
    perldoc perlrun: how to execute the Perl interpreter: command line switches
    perldoc perlvar: Perl predefined variables

    【讨论】:

      【解决方案3】:

      您能否尝试在 GNU awk 中使用所示示例进行跟踪、编写和测试。有一个名为 lines 的变量,我们可以在其中放置匹配模式后需要打印的行数。

      awk -v lines="2" '
      /^stringA/ && !/stringB/{
        count=0
        found=1
        print
        next
      }
      found && ++count<=lines
      '  Input_file
      

      说明:为上述添加详细说明。

      awk -v lines="2" '           ##Starting awk program from here and setting lines variabnle value to 2.
      /^stringA/ && !/stringB/{    ##Checking condition if line contains stringA and DOES NOT contain stringB then do following.
        count=0                    ##Setting count variable to 0 here.
        found=1                    ##Setting found variable to 1 here.
        print                      ##Printing current line here.
        next                       ##next will skip statements from here.
      }
      found && ++count<=lines      ##Checking condition if found is SET and count(with increasing value of 1) is lesser than lines then print that line.
      ' Input_file                 ##Mentioning Input_file name here.
      

      【讨论】:

        【解决方案4】:

        使用grep -P,您需要负前瞻:

        ^stringA(?!.*stringB).*$[\r\n]+.*[\r\n]+.*
        

        【讨论】:

        • 但是如果stringBstringA 之前呢?我更喜欢捕捉完整的线条,并进行积极的后视和消极的后视。
        • @rittergig 询问 OP。根据他们的^stringA,我假设他们对以stringA开头的行感兴趣
        • @rittergig 如果您有兴趣,那么^(?=.*stringA)(?!.*stringB).*$ 将实现这一目标。
        【解决方案5】:

        我不知道 grep 语法,但这是对我有用的正则表达式(.NET 正则表达式引擎):
        ^.*$(?&lt;=stringA.*)(?&lt;!stringB.*)

        您捕获了一条完整的线,然后进行了两次后视。

        我必须启用多行选项/m

        在 .NET 中测试它:

        Regex newRegex = new Regex(
            @"^.*$(?<=stringA.*)(?<!stringB.*)",
            RegexOptions.Multiline
        );
        

        【讨论】:

        • 问题是关于grep,而不是C#。
        • 这个正则表达式也应该与 grep 中使用的引擎兼容。
        • 不,grep 只能支持 PCRE 而 PCRE 不支持无限宽度的后视模式。
        猜你喜欢
        • 2015-12-25
        • 2022-01-19
        • 2021-07-09
        • 1970-01-01
        • 2019-01-20
        • 2018-10-05
        • 1970-01-01
        • 2019-01-14
        • 1970-01-01
        相关资源
        最近更新 更多