2013-05-09 3 views
3

У меня проблемы с grep и awk. Я думаю, это потому, что мой входной файл содержит текст, который выглядит как код.Соответствие текста с помощью grep или awk

Входной файл содержит имена идентификаторов и выглядит следующим образом:

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 идентификаторов.

Любые предложения или более простые способы сделать это будут замечательными.

ответ

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 содержит идентификатор в source.file в качестве подстроки. Вы можете построить более точную модель для grep на лету с sed:

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

Но таким образом шаблоны интерпретируются как регулярные выражения, а не в качестве фиксированных строк, которые потенциально уязвимы (хотя может быть хорошо, если идентификаторы содержат только буквенно-цифровые символы). Лучший способ, хотя (благодаря @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' в ссылке ЭСТА. –

+0

@sudo_O Хорошая точка, спасибо –

+2

Мы можем использовать «fgrep -wf source.file reference.file», чтобы избежать ложных срабатываний. –

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 
Смежные вопросы