Интервальные выражения в gawk to awk - PullRequest
2 голосов
/ 25 мая 2020

Надеюсь, это простое исправление

Изначально я написал чистый и простой скрипт, который использовал gawk, я использовал его в первую очередь потому, что когда я решал исходную проблему, я нашел то, что я нашел. Теперь мне нужно адаптировать его для использования только awk.

образец файла .fasta:

>gene1

>gene235
ATGCTTAGATTTACAATTCAGAAATTCCTGGTCTATTAACCCTCCTTCACTTTTCACTTTTCCCTAACCCTTCAAAATTTTATATCCAATCTTCTCACCCTCTACAATAATACATTTATTATCCTCTTACTTCAAAATTTTT

>gene335
ATGCTCCTTCTTAATCTAAACCTTCAAAATTTTCCCCCTCACATTTATCCATTATCACCTTCATTTCGGAATCCTTAACTAAATACAATCATCAACCATCTTTTAACATAACTTCTTCAAAATTTTACCAACTTACTATTGCTTCAAAATTTTTCAT

>gene406
ATGTACCACACACCCCCATCTTCCATTTTCCCTTTATTCTCCTCACCTCTACAATCCCCTTAATTCCTCTTCAAAATTTTTGGAGCCCTTAACTTTCAATAACTTCAAAATTTTTCACCATACCAATAATATCCCTCTTCAAAATTTTCCACACTCACCAAC


gawk '/[ACTG]{21,}GG/{print a; print}{a=$0}' file.fasta >"species_precrispr".fasta

то, что, как я знаю, работает, это awk следующее:

awk '/[ACTG]GG/{print a; print}{a=$0}' file.fasta >"species_precrispr".fasta

виновником, следовательно, является интервальное выражение {21,}

Я хочу, чтобы он выполнял поиск по каждой строке, содержащей по крайней мере 21 нуклеотид, оставшийся от моего совпадения "GG".

Может кто поможет?

Изменить:

Спасибо за помощь: есть различные решения, которые сработали. Чтобы ответить на некоторые из комментариев, приведем более c базовый пример начального вывода и достигнутого желаемого эффекта ...

Перед командой awk: cat file1.fasta

>gene1
ATGCCTTAACTTTCAATAACTGG 
>gene2
ATGGGTGCCTTAACTTTCAATAACTG
>gene3
ATGTCAAAATTTTTCATTTCAAT
>gene4
ATCCTTTTTTTTGGGTCAAAATTAAA
>gene5
ATGCCTTAACTTTCAATAACTTTTTAAAATTTTTGG

Все следующие коды производили одинаковый желаемый результат:

исходный код

gawk '/[ACTG]{21,}GG/{print a; print}{a=$0}' file1.fasta 

небольшая модификация, которая добавляет функцию интервала к исходной версии awk> 3.xx

awk --re-interval'/[ACTG]{21,}GG/{print a; print}{a=$0}' file1.fasta

Позволяет для модификации val и правильного вывода, непроверено, но должно работать с более низкими версиями awk

awk -v usr_count="21" '/gene/{id=$0;next} match($0,/.*GG/){val=substr($0,RSTART,RLENGTH-2);if(gsub(/[ACTG]/,"&",val)>= usr_count){print id ORS $0};id=""}' file1.fasta

awk --re-interval '/^>/ && seq { if (match(seq,"[ACTG]{21,}GG")) print ">" name ORS seq ORS} /^>/{name=$0; seq=""; next} {seq = seq $0 } END { if (match(seq,"[ACTG]{21,}GG")) print ">" name ORS seq ORS }' file1.fasta

Желаемый результат: захватить только имена генов и последовательности последовательностей, которые имеют 21 нуклеотид до соответствия GG

>gene1
ATGCCTTAACTTTCAATAACTGG 
>gene5
ATGCCTTAACTTTCAATAACTTTTTAAAATTTTTGG

Наконец, чтобы показать отброшенные строки

>gene2
ATG-GG-TGCCTTAACTTTCAATAACTG # only 3 nt prior to any GG combo 
>gene3
ATGTCAAAATTTTTCATTTCAAT # No GG match found 
>gene4
ATCCTTTTTTTTGGGTCAAAATTAAA # only 14 nt prior to any GG combo 

Надеюсь, это поможет другим!

Ответы [ 3 ]

2 голосов
/ 25 мая 2020

GNU awk принимает интервальные выражения в регулярных выражениях начиная с версии 3.0. Однако только с версии 4.0 интервальное выражение стало включенным по умолчанию. Если у вас есть awk 3.xx, вы должны использовать флаг --re-interval, чтобы включить их.

awk --re-interval '/a{3,6}/{print}' file

Существует проблема, которую люди часто не замечают при работе с файлами FASTA и использованием awk. Когда у вас есть многострочные последовательности, возможно, что ваше совпадение охватывает несколько строк. Для этого вам нужно сначала объединить свои последовательности.

Самый простой способ обработать файлы FASTA с помощью awk - создать переменную с именем name и переменную с именем seq. Каждый раз, когда вы читаете полную последовательность, вы можете обработать ее. Обратите внимание, что для наилучшего способа обработки последовательность должна быть сохранена как непрерывная строка и не должна содержать никаких новых строк или пробелов. Общий c awk для обработки fasta выглядит так:

awk '/^>/ && seq { **process_sequence_here** }
     /^>/{name=$0; seq=""; next}
     {seq = seq $0 }
     END { **process_sequence_here** }' file.fasta

В представленном случае ваша обработка последовательности выглядит так:

awk '/^>/ && seq { if (match(seq,"[ACTG]{21,}GG")) print ">" name ORS seq ORS}
     /^>/{name=$0; seq=""; next}
     {seq = seq $0 }
     END { if (match(seq,"[ACTG]{21,}GG")) print ">" name ORS seq ORS }' file.fasta
2 голосов
/ 25 мая 2020

РЕДАКТИРОВАТЬ: В соответствии с комментарием OP необходимо также распечатать идентификаторы генов, затем попробуйте следующее.

awk '
/gene/{
  id=$0
  next
}
match($0,/.*GG/){
  val=substr($0,RSTART,RLENGTH-2)
  if(gsub(/[ACTG]/,"&",val)>=21){
    print id ORS $0
  }
  id=""
}
' Input_file

ИЛИ однострочная форма вышеуказанного решения в соответствии с Запрос OP:

awk '/gene/{id=$0;next} match($0,/.*GG/){val=substr($0,RSTART,RLENGTH-2);if(gsub(/[ACTG]/,"&",val)>=21){print id ORS $0};id=""}' Input_file


Не могли бы вы попробовать следующие, написанные и протестированные только с показанными образцами.

awk '
match($0,/.*GG/){
  val=substr($0,RSTART,RLENGTH-2)
  if(gsub(/[ACTG]/,"&",val)>=21){
    print
  }
}
' Input_file

ИЛИ более общий c подход, где был создан переменная, в которой пользователь может указать значение, которое пользователь хочет сопоставить, должна присутствовать перед GG.

awk -v usr_count="21" '
match($0,/.*GG/){
  val=substr($0,RSTART,RLENGTH-2)
  if(gsub(/[ACTG]/,"&",val)>=usr_count){
    print
  }
}
'  Input_file

Пояснение: Добавление подробного объяснения выше.

awk '                                ##Starting awk program from here.
match($0,/.*GG/){                    ##Using Match function to match everything till GG in current line.
  val=substr($0,RSTART,RLENGTH-2)    ##Storing sub-string of current line from RSTART till RLENGTH-2 into variable val here.
  if(gsub(/[ACTG]/,"&",val)>=21){    ##Checking condition if global substitution of ACTG(with same value) is greater or equal to 21 then do following.
    print                            ##Printing current line then.
  }
}
' Input_file                         ##Mentioning Input_file name here.
1 голос
/ 26 мая 2020

Похоже, что вы хотите:

awk 'match($0,/[ACTG]+GG/) && RLENGTH>22{print a; print} {a=$0}' file

, но это, вероятно, все, что вам нужно, учитывая предоставленный вами образец ввода:

awk 'match($0,/.*GG/) && RLENGTH>22{print a; print} {a=$0}' file

Они оба будут работать в любом awk .

Используя обновленный образец ввода:

$ awk 'match($0,/.*GG/) && RLENGTH>22{print a; print} {a=$0}' file
>gene1
ATGCCTTAACTTTCAATAACTGG
>gene5
ATGCCTTAACTTTCAATAACTTTTTAAAATTTTTGG
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...