#unix #awk #bioinformatics
Вопрос:
В настоящее время я учусь использовать awk и нашел нужную мне команду awk, но не до конца понимаю, что происходит. Эта строка кода берет файл генома, называемый fasta, и возвращает всю длину каждой последовательности в нем. Для тех, кто не знаком с файлами fasta, это текстовые файлы, которые могут содержать несколько генетических последовательностей, называемых смежными. Это следует общей структуре:
>Nameofsequence
Sequencedata like: ATGCATCG
GCACGACTCGCTATATTATA
>Nameofsequence2
Sequencedata
Строка находится здесь:
cat file.fa | awk '$0 ~ ">" {if (NR > 1) {print c;} c=0;printf substr($0,2,100) "t"; } $0 !~ ">" {c =length($0);} END { print c; }'
Я понимаю, что кот открывает файл fasta, проверяет, соответствует ли его строка имени последовательности, и в какой-то момент подсчитывает количество символов в разделе данных. Но я не понимаю, как он разбивает раздел данных на подстроки и как он сбрасывает количество с каждой новой последовательностью.
ПРАВКА Эда Мортона: вот приведенный выше сценарий awk, отформатированный разборчиво gawk -o-
:
$0 ~ ">" {
if (NR > 1) {
print c
}
c = 0
printf substr($0, 2, 100) "t"
}
$0 !~ ">" {
c = length($0)
}
END {
print c
}
Комментарии:
1. Если вы зададите какие-либо вопросы в будущем, пожалуйста, не публикуйте страшный «онлайн», чтобы мы попытались прочитать, опубликуйте сценарий, который будет отформатирован с новыми строками и отступами, которые подчеркивают поток управления вашей программой. Если это awk-скрипт, и вы не можете найти для него хороший макет, просто запустите его с помощью
gawk -o- 'script'
, и он будет распечатан для вас. Я просто сделал это для вас по этому вопросу.
Ответ №1:
Сначала отформатируйте команду:
awk '
$0 ~ ">" {
if (NR > 1) {print c;}
c=0;
printf substr($0,2,100) "t";
}
$0 !~ ">" {
c =length($0);
}
END { print c; }
' file.fa
Код будет использоваться c
для подсчета символов.Этот счетчик начинается со значения 0 и будет сбрасываться до 0 каждый раз, когда строка с >
анализируется.
Длина входной строки добавляется c
, если входная строка не содержит a >
.
Значение c
должно быть напечатано после последовательности, поэтому, когда оно находит новое >
(не в первой строке) или когда анализируется полный файл (блок с END
).
Как вы, возможно, уже сейчас понимаете:
breaking down the data section in substrings
заключается в сопоставлении входной строки с a >
, и
resetting the counts with each new sequence
делается с помощью c=0
в блоке с. $0 ~ ">"
Посмотрите на комментарий Эда: printf
утверждение используется неправильно. Я не знаю, как часто %s встречается в файле fasta, но это не важно: используйте %s
для входных строк.
Комментарии:
1. Никогда
printf input
не используйте для каких-либо входных значений, так как это приведет к сбою, если входные данные содержат символы форматирования printf, например%s
. Так что вместоprintf substr($0,2,100) "t"
использованияprintf "%st", substr($0,2,100)
Ответ №2:
@Walterа уже ответил на ваш вопрос, объяснив, что делает скрипт, но в случае, если вам интересно вот улучшенная версия, включая несколько небольших исправлений для использования printf input
и печать пустой строки, если входной файл пуст и улучшений по сравнению с избыточными измерениями одного и того же состояния дважды и тестирование >
и удаление его отдельно, а не все сразу:
BEGIN { OFS="t" }
sub(/^>/,"") {
if (lgth) { print name, lgth }
name = $0
lgth = 0
next
}
{ lgth = length($0) }
END {
if (lgth) { print name, lgth }
}
В качестве альтернативы вы могли бы сделать:
BEGIN { OFS="t" }
sub(/^>/,"") {
if (seq != "") { print name, length(seq) }
name = $0
seq = ""
next
}
{ seq = seq $0 }
END {
if (seq != "") { print name, length(seq) }
}
но добавление к переменной происходит медленно, поэтому вызов функции length() для каждой строки последовательности может быть более эффективным.
Комментарии:
1. Вы можете избежать
next
сBEGIN { OFS="t" } split ($0,a,">")==2 { if (lgth) { print name, lgth } name = a[2] lgth = 0 } {lgth = length(a[1]) } END { if (lgth) { print name, lgth } }
2. Мне это кажется менее ясным и менее эффективным, чем использование
next
.3. Правда, дальше все более понятно. Другое решение заключается в
awk 'BEGIN { RS=">"; FS="n"; OFS="" } { name=$1; $1=""; lgth=length($0); if (lgth) { printf("%st%sn", name, lgth) } }' file.fa