【问题标题】:print rows that match exact pattern using awk使用 awk 打印与精确模式匹配的行
【发布时间】:2020-10-12 09:01:55
【问题描述】:

我有一个带有名称的文件,我想在一个巨大的制表符分隔文件中搜索它们并获取相应的行。我需要匹配确切的名称。所以我尝试了这个 grep 选项,我使用名称文件 (-f) 搜索一个大文件,并指定我想要 完全匹配 (-w)。

grep -f names -w bigfile > outputfile

由于制表符分隔文件很大,grep 命令耗时太长,所以我正在寻找一个 awk 替代方案。到目前为止,我尝试过:

awk 'NR==FNR{a[$0]=$0}NR>FNR{if($2==a[$2])print $0}' names bigfile > outputfile

在这里,我在大文件的第 2 列中查找匹配项并打印相应的行。

问题是这个 awk 选项不是特定的。有没有人建议如何修改这个单行符,使其与正则表达式完全匹配?

编辑

这是一个例子:

假设名称文件如下所示:

GN2a__NODE_1000349_length_1013_cov_0.309117_1
GN4a__NODE_1000349_length_1013_cov_0.303417_1
GN3a__NODE_1000343_length_1013_cov_0.309417_2
GN2a__NODE_1020349_length_1013_cov_0.109437_1
GN2a__NODE_1020349_length_1013_cov_0.109437_10
GO4a__NODE_9_length_201043_cov_2.340371_8
GO4a__NODE_9_length_201043_cov_2.340371_83

制表符分隔的大于 800 万行的大文件的前 9 行如下所示:

7001253F:563:CC1HJANXX:8:2210:1232:2187#CTGAAGCTCAGGACGT    GN2a__NODE_1000349_length_1013_cov_0.309117_1      
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GN4a__NODE_1000349_length_1013_cov_0.303417_1  
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GN3a__NODE_1000343_length_1013_cov_0.309417_2
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GN2a__NODE_1020349_length_1013_cov_0.109437_1
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GN2a__NODE_1020349_length_1013_cov_0.109437_10
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GN2a__NODE_1020349_length_1013_cov_0.109437_14
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GO4a__NODE_9_length_201043_cov_2.340371_8
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GO4a__NODE_9_length_201043_cov_2.340371_83
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GO4a__NODE_9_length_201043_cov_2.340371_87

我希望我的输出如下所示:

7001253F:563:CC1HJANXX:8:2210:1232:2187#CTGAAGCTCAGGACGT    GN2a__NODE_1000349_length_1013_cov_0.309117_1     
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GN4a__NODE_1000349_length_1013_cov_0.303417_1  
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GN3a__NODE_1000343_length_1013_cov_0.309417_2
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GN2a__NODE_1020349_length_1013_cov_0.109437_1
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GN2a__NODE_1020349_length_1013_cov_0.109437_10
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GO4a__NODE_9_length_201043_cov_2.340371_8
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GO4a__NODE_9_length_201043_cov_2.340371_83

而使用 awk 单行,我得到:

7001253F:563:CC1HJANXX:8:2210:1232:2187#CTGAAGCTCAGGACGT    GN2a__NODE_1000349_length_1013_cov_0.309117_1      
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GN4a__NODE_1000349_length_1013_cov_0.303417_1  
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GN3a__NODE_1000343_length_1013_cov_0.309417_2
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GN2a__NODE_1020349_length_1013_cov_0.109437_1
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GN2a__NODE_1020349_length_1013_cov_0.109437_10
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GO4a__NODE_9_length_201043_cov_2.340371_8
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GO4a__NODE_9_length_201043_cov_2.340371_83
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GO4a__NODE_9_length_201043_cov_2.340371_87

【问题讨论】:

  • 欢迎来到 SO,感谢您以代码的形式展示您的努力,继续努力。您能否在您的问题中也发布输入和预期输出的小/合理样本数据集,以便我们对此有更多了解,请编辑您的问题并让我们知道。
  • 另外,通过看到您的尝试看起来您正在处理 2 个 Input_file(s),因此请在您的问题中发布它们两个样本的小 sn-p 样本以及预期的样本输出。跨度>

标签: regex awk grep pattern-matching


【解决方案1】:

这是join 要做的工作:

$ join -t$'\t' -1 1 -2 2 -o '2.1 2.2' <(sort names) <(sort -k2,2 bigfile)
7001253F:563:CC1HJANXX:8:2210:1232:2187#CTGAAGCTCAGGACGT    GN2a__NODE_1000349_length_1013_cov_0.309117_1
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GN2a__NODE_1020349_length_1013_cov_0.109437_1
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GN2a__NODE_1020349_length_1013_cov_0.109437_10
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GN3a__NODE_1000343_length_1013_cov_0.309417_2
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GN4a__NODE_1000349_length_1013_cov_0.303417_1
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GO4a__NODE_9_length_201043_cov_2.340371_8
7001253F:563:CC1HJANXX:8:2210:1968:2031#CTGAAGCTCAGGACGT    GO4a__NODE_9_length_201043_cov_2.340371_83

【讨论】:

    【解决方案2】:

    你的解释不是很清楚。似乎您正在尝试进行精确的文字匹配,而不是正则表达式。

    $ awk -F'\t' 'NR==FNR{a[$1]; next} $2 in a' names bigfile > outputfile
    

    即使您在第一个字段中有空格也应该有效。但是,我希望文字 grep 匹配比这更快。

    请注意,这与其他 awk 脚本几乎相同。

    【讨论】:

      【解决方案3】:

      我看不出您的单线有什么问题,尽管可以将其简化为稍微提高性能

      awk 'NR==FNR{a[$0]} NR>FNR{if($2 in a)print $0}' names bigfile >outputfile
      

      或者更紧凑一些

      awk 'NR==FNR{a[$0]} NR>FNR && $2 in a' names bigfile >outputfile
      

      我的猜测是您的名称文件中存在不可见的控制字符,这些字符会影响输出

      我也很惊讶你发现 grep 比 awk 慢。我对您的数据重复到 300 万行的测试表明 grep 比 awk 快 3 倍

      你是在 Linux 上运行它吗?这是 GNU grep 和 awk 吗?

      【讨论】:

      • 您好,感谢您的回复!是的,对于你的两个问题:) 我意识到当我在 grep 上添加 -w 选项时它只会变慢。有很多试验和错误涉及。我实际上是根据我之前发现的错误组成了这个虚拟数据集。我运行了代码,它适用于这个虚拟数据集,所以我很尴尬,甚至用这个数据提出了这个问题。我主要只是想要求一个 awk -w 等价物,因为它存在于 grep
      • 好的 - 这不应该发生在基本匹配中 - grep 应该比 awk 快得多
      • NR==FNR{a[$0]} NR&gt;FNR{if($2 in a)print $0} 更常见/习惯上写为NR==FNR{a[$0];next} $2 in a,请参阅stackoverflow.com/a/62521989/1745001
      【解决方案4】:

      编辑:由于 OP 的示例已完全更改,因此现在添加此解决方案,再次仅基于显示的示例。

      awk '
      FNR==NR{
        a[$0]
        next
      }
      match($0,/[[:alnum:]]+__NODE_[0-9]+_length.*cov_[0-9]+\.[0-9]+_[0-9]+/) && (substr($0,RSTART,RLENGTH) in a)
      ' names Input_file
      


      您能否尝试仅在 GNU awk 中对所示示例进行跟踪、编写和测试。

      awk '
      FNR==NR{
        a[$0]
        next
      }
      match($0,/Gene[0-9]+/) && (substr($0,RSTART,RLENGTH) in a)
      ' names Input_file
      

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

      awk '                                   ##Starting awk program from here.
      FNR==NR{                                ##Checking condition FNR==NR which will be TRUE when first Input_file is being read.
        a[$0]                                 ##Creating array a with index of current line here.
        next                                  ##next will skip all further statement from here.
      }
      match($0,/Gene[0-9]+/) && (substr($0,RSTART,RLENGTH) in a)    ##Matching regex of Gene digits(which are coing together) AND making sure this substring(which is actually matched value by regex) is present in names file array then print current line.
      ' names  Input_file                     ##Mentioning Input_file names here.
      

      【讨论】:

      • 感谢您的解释!这可能行得通,但我的“名称”文件比“基因”更复杂。我意识到我应该在之前提到过。我编辑了帖子。
      • @joanaseneca,它现在完全改变了 :) 让我在几分钟内编辑解决方案并返回 :)
      • @joanaseneca,您能否检查一下 EDIT 解决方案,让我知道它是怎么回事?
      • 好吧!!这行得通! :D 我现在要高档!非常感谢!
      • @joanaseneca,您可以查看此链接 meta.stackexchange.com/a/5235/380336 一次,在这个伟大的论坛上欢呼和快乐学习 :)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-15
      • 1970-01-01
      • 2011-07-20
      • 2022-01-16
      • 1970-01-01
      • 2013-07-28
      相关资源
      最近更新 更多