【问题标题】:Matching text using grep or awk使用 grep 或 awk 匹配文本
【发布时间】:2013-05-09 09:01:27
【问题描述】:

我遇到了 grep 和 awk 的问题。我认为这是因为我的输入文件包含看起来像代码的文本。

输入文件包含 ID 名称,如下所示:

SNORD115-40
MIR432
RNU6-2

参考文件如下所示:

Ensembl Gene ID HGNC symbol
ENSG00000199537 SNORD115-40
ENSG00000207793 MIR432
ENSG00000266661
ENSG00000243133
ENSG00000207447 RNU6-2

我想将源文件中的 ID 名称与参考文件匹配,并打印出相应的 ensg ID 号,以便输出文件如下所示:

ENSG00000199537 SNORD115-40
ENSG00000207793 MIR432
ENSG00000207447 RNU6-2

我试过这个循环:

exec < source.file
while read line
do
grep -w $line reference.file > outputfile
done

我也尝试过使用 awk 处理参考文件

awk 'NF == 2 {print $0}' reference file
awk 'NF >2 {print $0}' reference file

但我只得到一个 grep 的 ID。

任何建议或更简单的方法都会很棒。

【问题讨论】:

    标签: awk grep


    【解决方案1】:
    $ fgrep -f source.file reference.file 
    ENSG00000199537 SNORD115-40
    ENSG00000207793 MIR432
    ENSG00000207447 RNU6-2
    

    fgrep 等价于grep -F

       -F, --fixed-strings
              Interpret  PATTERN  as  a  list  of  fixed strings, separated by
              newlines, any of which is to be matched.  (-F  is  specified  by
              POSIX.)
    

    -f 选项用于从文件中获取PATTERN

       -f FILE, --file=FILE
              Obtain  patterns  from  FILE,  one  per  line.   The  empty file
              contains zero patterns, and therefore matches nothing.   (-f  is
              specified by POSIX.)
    

    如 cmets 中所述,如果 reference.file 中的 ID 包含 source.file 中的 ID 作为子字符串,这可能会产生误报。您可以使用sed 即时为grep 构建更明确的模式:

    grep -f <( sed 's/.*/ &$/' input.file) reference.file
    

    但是这种方式将模式解释为正则表达式而不是固定字符串,这可能是易受攻击的(尽管如果 ID 仅包含字母数字字符则可能没问题)。不过,更好的方法(感谢@sidharthcnadhan)是使用-w 选项:

       -w, --word-regexp
              Select  only  those  lines  containing  matches  that form whole
              words.  The test is that the matching substring must  either  be
              at  the  beginning  of  the  line,  or  preceded  by  a non-word
              constituent character.  Similarly, it must be either at the  end
              of  the  line  or  followed by a non-word constituent character.
              Word-constituent  characters  are  letters,  digits,   and   the
              underscore.
    

    所以你的问题的最终答案是:

    grep -Fwf source.file reference.file
    

    【讨论】:

    • 这将产生误报,即输入文件中的 SNORD115-40 也将匹配参考文件中的 SNORD115-401 等。
    • 我们可以使用“fgrep -wf source.file reference.file”来避免误报。
    【解决方案2】:

    这样就可以了:

    $ awk 'NR==FNR{a[$0];next}$NF in a{print}' input reference
    ENSG00000199537 SNORD115-40
    ENSG00000207793 MIR432
    ENSG00000207447 RNU6-2
    

    【讨论】:

      【解决方案3】:

      这是一个不错的bashish 尝试。问题是您总是覆盖结果文件。使用 '>>' 代替 &gt; 或将 &gt; 移动到 done 之后

      grep -w $line reference.file >> outputfile
      

      done  > outputfile
      

      但我更喜欢 Lev 的解决方案,因为它只启动一次外部进程。

      如果你想用纯bash解决它,你可以试试这个:

      ID=($(<IDfile))
      
      while read; do
         for((i=0;i<${#ID[*]};++i)) {
             [[ $REPLY =~ [[:space:]]${ID[$i]}$ ]] && echo $REPLY && break
         }
      done <RefFile >outputfile
      
      cat outputfile
      

      输出:

      ENSG00000199537 SNORD115-40
      ENSG00000207793 MIR432
      ENSG00000207447 RNU6-2
      

      较新的bash 支持关联数组。它可用于简化和加快键的搜索:

      declare -A ID
      for i in $(<IDfile); { ID[$i]=1;}
      
      while read v; do
         [[ $v =~ [[:space:]]([^[:space:]]+)$ && ${ID[${BASH_REMATCH[1]}]} = 1 ]] && echo $v
      done <RefFile
      

      【讨论】:

        猜你喜欢
        • 2014-10-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-17
        • 1970-01-01
        • 1970-01-01
        • 2021-12-26
        • 1970-01-01
        相关资源
        最近更新 更多