【问题标题】:How can I grep everything except the pattern and its next n lines?除了模式及其下 n 行之外,我如何 grep 其他所有内容?
【发布时间】:2014-09-08 20:32:46
【问题描述】:

我有一个文件:

names.dat:

AAAA
BBBB

文本.dat:

AAAA
CTGCTTCGTCA
12127567612
BBBB
TCGACTACTAG
12331276318
CCCC
TCATCATACAT
23612763812
DDDD
GCTATCGCATC
23767263723

我要做的是(仅使用 shell 命令)从 text.dat 中排除那些也存在于 names.dat 中的行,以及(最重要的是)公共行之后的三行。

所以基本上输出应该看起来像:

CCCC
TCATCATACAT
23612763812
DDDD
GCTATCGCATC
23767263723

【问题讨论】:

    标签: regex bash shell grep


    【解决方案1】:

    您可以使用 awk 做到这一点:

    awk 'NR==FNR {a[$0]; next} $0 in a {i=0} ++i>3' names.dat text.dat
    

    NR==FNR 表示总记录数等于当前文件的记录数(这仅适用于第一个文件)。使用names.dat 的行来设置数组a 中的键。 next 跳到输入的下一行,忽略单行中的任何其他命令。每当text.dat 中的一行与a 的元素匹配时,计数器i 就会重置为0。仅当i 大于3 时才会打印行。

    测试一下:

    $ awk 'NR==FNR {a[$0]; next} $0 in a {i=0} ++i>3' names.dat text.dat 
    CCCC
    TCATCATACAT
    23612763812
    DDDD
    GCTATCGCATC
    23767263723
    

    【讨论】:

      【解决方案2】:

      如果 text.dat 中的每一行都是唯一的:

      grep -Fxvf <(grep -f names.dat -A 2 text.dat | grep -v '^--' ) text.dat
      

      输出:

      中国交建 TCCATCATACAT 23612763812 DDDD GCTATCGCATC 23767263723

      【讨论】:

      • 我很想走类似的路线。值得一提的是,如果名称是固定的,您可以使用-F 和/或-x 来匹配固定字符串而不是正则表达式,并且只匹配整行。
      • 我同意你的看法。谢谢你。我已经更新了我的答案以避免匹配子字符串。
      • 我添加了grep -v '^--',因为这个问题/问题:stackoverflow.com/q/25733264/3776858
      • 如果CCCC下面的一行和AAAA下面的一行一样怎么办?
      • @lihao:见我第一句话的限制。
      【解决方案3】:

      如果:

      1. 文件中没有标签,并且

      2. 模式中没有正则表达式元字符,则:

        paste -sd'\t\t\n' text.dat |
        grep -v -f <(mapfile -t a <names.dat;printf '^%s\t\n' "${a[@]}") |
        tr \\t \\n
        

      如果需要的话,它的优点是它可以真正比较每三个一组的行。

      【讨论】:

        【解决方案4】:

        您可以使用grep 命令来做到这一点。

        grep -v "`grep -f name.dat -A 2 text.dat`" text.dat
        

        输出如下。

        CCCC
        TCATCATACAT
        23612763812
        DDDD
        GCTATCGCATC
        23767263723
        

        备注: text.dat 必须在“AAAA”和“BBBB”之间有 2 行,还有“BBBB”和“CCCC”,因为“2”是幻数...

        【讨论】:

          【解决方案5】:

          正则表达式在反转下是封闭的。这意味着如果您可以使用正则表达式匹配 x,则可以使用正则表达式匹配除 x 之外的所有内容。

          假设(AAAA\n|BBBB\n) 是您的模式,并且您想匹配该模式和接下来的三行。 (与您的问题相反。)请注意,\n 表示换行符。

          (AAAA\n|BBBB\n)([^\n]*\n){3} 会得到这个。 [^\n] 表示“除换行符之外的所有内容”。这个表达式找到你的模式,加上三个完整的行。 (由于grep 不支持大括号符号,您应该使用egrep。)

          传递参数-v 以反转表达式。

          【讨论】:

          • 你应该试试;您会发现几个问题: (1) 除非您指定 -E(或 Gnu grep 中的 -P),否则 ({ 并不特殊。 (2) 你的意思当然是[^\n]*;如所写,该模式将仅匹配以下仅包含一个字符的行,除了 (3) grep 匹配 lines,而不是任意文本。所以你永远不能匹配模式中的换行符。
          • 逻辑无懈可击,但工具不配合。使用 grep,您无法匹配跨越多行的模式。 (实际上,您可以使用 gnu grep 执行此操作,但它涉及使用 -zo 并在模式中包含文字换行符或使用 -P。然后您需要手动进行反转,因为不再有多行。 )
          猜你喜欢
          • 1970-01-01
          • 2018-06-26
          • 2012-03-06
          • 2010-10-11
          • 1970-01-01
          • 2016-02-25
          • 1970-01-01
          • 2014-01-30
          • 2011-06-30
          相关资源
          最近更新 更多