2013-05-09 79 views
3

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

的输入文件中包含的ID名称,看起来像这样:

SNORD115-40 
MIR432 
RNU6-2 

参考文件看起来是这样的:

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

我想从我的源文件中的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'd ID之一。

任何建议或更简单的方法,这样做会很好。

回答

7
$ 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 OK只包含字母数字字符)。更好的方法,虽然(感谢@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 
+0

这会产生误报即'输入文件SNORD115-40'也将匹配'SNORD115-401'的参考等。 – 2013-05-09 09:15:00

+0

@sudo_O好点,谢谢 – 2013-05-09 09:22:13

+2

我们可以使用“fgrep -wf source.file reference.file”来避免误报。 – 2013-05-09 09:30:03

4

这将这样的伎俩:

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

这是一个不错的bash十岁上下的尝试。问题是你总是覆盖结果文件。使用“>>”而不是>或移动>done

grep -w $line reference.file >> outputfile 

done > outputfile 

但它启动一个外部进程只有一次,我宁愿列弗的解决方案。

如果你想解决它在纯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