使用grep或awk匹配文本

时间:2013-05-09 09:01:27

标签: awk grep

我遇到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'dID。

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

3 个答案:

答案 0 :(得分:8)

$ 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.)

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

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

答案 1 :(得分:4)

这样可以解决问题:

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

答案 2 :(得分:1)

这是一个不错的bash尝试。问题是您始终覆盖结果文件。使用'&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