Извлечь строки, содержащие два шаблона - PullRequest
0 голосов
/ 07 декабря 2018

У меня есть файл, который содержит несколько строк следующим образом:

>header1
<pattern_1>CGGCGGGCAGATGGCCACCAACAACCAGAGCTCCCTGGCCGGGCCTCTTTTCCTGACGGCCGCCCCCACTGCCCCCACGACCGGCCCGTACAAC<pattern_2>
>header2
<pattern_1>CGGCGGGCAGATGGCCACCAACAACCAGAGCTCCCTGGCCTGCAATCACTACTCGTGTTTTGCCACCACTGCCCCCACGACCGGCACGTACAAC<pattern_2>
>header3
<pattern_1>ATGGCCACCAACAACCAGAGCTCCC
>header4
GACCGGCACGTACAACCTCCAGGAAATCGTGCCCGGCAGCGTGTGGATGGAGAGGGACGTG
>header5
TGCCCCCACGACCGGCACGTACAAC<pattern_2>

Я хочу извлечь все строки, содержащие обе строки, включая строки заголовков.

Я пробовал использовать grep, ноон извлекает только строки последовательности, но не строки заголовка.

grep <pattern_1> | grep <pattern_2> input.fasta > output.fasta

Как извлечь строки, содержащие как шаблоны, так и заголовки в Linux?Шаблоны могут присутствовать где угодно в строках.Не ограничивается началом или концом строк.

Ожидаемый результат:

>header1
<pattern_1>CGGCGGGCAGATGGCCACCAACAACCAGAGCTCCCTGGCCGGGCCTCTTTTCCTGACGGCCGCCCCCACTGCCCCCACGACCGGCCCGTACAAC<pattern_2>
>header2
<pattern_1>CGGCGGGCAGATGGCCACCAACAACCAGAGCTCCCTGGCCTGCAATCACTACTCGTGTTTTGCCACCACTGCCCCCACGACCGGCACGTACAAC<pattern_2>

Ответы [ 5 ]

0 голосов
/ 07 декабря 2018

Возможно, вас заинтересует BioAwk , это адаптированная версия awk, настроенная для обработки файлов fasta

bioawk -c fastx -v seq1="pattern1" -v seq2="pattern2" \
       '($seq ~ seq1) && ($seq ~ seq2) { print ">"$name; print $seq }' file.fasta

Если вы хотите seq1 в начале и seq2 в конце вы можете изменить его на:

bioawk -c fastx -v seq1="pattern1" -v seq2="pattern2" \
       '($seq ~ "^"seq1) && ($seq ~ seq2"$") { print ">"$name; print $seq }' file.fasta

Это действительно удобно для обработки файлов fasta, так как часто последовательность разбивается на несколько строк.Приведенный выше код обрабатывает это очень легко, поскольку переменная $seq содержит полную последовательность.

Если вы не хотите устанавливать BioAwk, вы можете использовать следующий метод для обработки файла FASTA.Он допускает многострочные последовательности и выполняет следующие действия:

  • читает по одной записи за раз (это предполагает отсутствие > в заголовке, кроме первого символа)
  • извлечь заголовок из записи и сохранить его в name (на самом деле не нужно)
  • объединить всю последовательность в одну строку символов, удалив все символы новой строки и пробелы.Это гарантирует, что поиск pattern1 или pattern2 не завершится неудачей, если шаблон разбит на несколько строк.
  • , если совпадение найдено, напечатайте запись.

следующий awk выполняет запрошенный запрос:

awk -v seq1="pattern1" -v seq2="pattern2" \
    'BEGIN{RS=">"; ORS=""; FS="\n"}
     { seq="";for(i=2;i<=NF;++i) seq=seq""$i; gsub(/[^a-zA-Z0-9]/,"",seq) }
     (seq ~ seq1 && seq ~ seq2){print ">" $0}' file.fasta

Если заголовок записи содержит другие символы >, которые не находятся в начале строки, вы должны использовать немного другой подход (если вы не используете GNU awk)

awk -v seq1="pattern1" -v seq2="pattern2" \
    '/^>/ && (seq ~ seq1 && seq ~ seq2) {
         print name
         for(i=0;i<n;i++) print aseq[i]
     }
     /^>/ { seq=""; delete aseq; n=0; name=$0; next }
     { aseq[n++] = $0; seq=seq""$0; sub(/[^a-zA-Z0-9]*$/,"",seq) }
     END { if (seq ~ seq1 && seq ~ seq2) {
              print name
              for(i=0;i<n;i++) print aseq[i]
            }
     }' file.fasta

примечание: здесь мы используем sub в случае, если в файле fasta введены непредвиденные символы (например, пробелы / табуляции или CR (\r))


Примечание: BioAwk основан на awk Брайана Кернигана , который задокументирован в "Языке программирования AWK"Аль Ахо, Брайаном Керниганом и Питером Вайнбергером (Addison-Wesley, 1988, ISBN 0-201-07981-X) .Я не уверен, что эта версия совместима с POSIX .

0 голосов
/ 07 декабря 2018

Если ваш входной файл в точности соответствует описанию в вашем посте, вы можете использовать:

grep -B1 '^<pattern_1>.*<pattern_2>$' input 
>header1
<pattern_1>CGGCGGGCAGATGGCCACCAACAACCAGAGCTCCCTGGCCGGGCCTCTTTTCCTGACGGCCGCCCCCACTGCCCCCACGACCGGCCCGTACAAC<pattern_2>
>header2
<pattern_1>CGGCGGGCAGATGGCCACCAACAACCAGAGCTCCCTGGCCTGCAATCACTACTCGTGTTTTGCCACCACTGCCCCCACGACCGGCACGTACAAC<pattern_2>

Где -B1 будет отображать в верхней части соответствующих строк строку перед ним.Используемое регулярное выражение основано на гипотезе, что ваши 2 паттерна расположены в точном порядке в начале и в конце строки.Если это не так: используйте '.*<pattern_1>.*<pattern_2>.*'.И последнее, но не менее важное: если порядок двух шаблонов не всегда соблюдается, вы можете использовать: '^.*<pattern_1>.*<pattern_2>.*$\|^.*<pattern_2>.*<pattern_1>.*$'

В следующем входном файле :

cat input
>header1
<pattern_1>CGGCGGGCAGATGGCCACCAACAACCAGAGCTCCCTGGCCGGGCCTCTTTTCCTGACGGCCGCCCCCACTGCCCCCACGACCGGCCCGTACAAC<pattern_2>
>header2
<pattern_1>CGGCGGGCAGATGGCCACCAACAACCAGAGCTCCCTGGCCTGCAATCACTACTCGTGTTTTGCCACCACTGCCCCCACGACCGGCACGTACAAC<pattern_2>
>header2b
<pattern_2>CGGCGGGCAGATGGCCACCAACAACCAGAGCTCCCTGGCCTGCAATCACTACTCGTGTTTTGCCACCACTGCCCCCACGACCGGCACGTACAAC<pattern_1>
>header3
<pattern_1>ATGGCCACCAACAACCAGAGCTCCC
>header4
GACCGGCACGTACAACCTCCAGGAAATCGTGCCCGGCAGCGTGTGGATGGAGAGGGACGTG
>header5
TGCCCCCACGACCGGCACGTACAAC<pattern_2>

выход:

grep -B1 '^.*<pattern_1>.*<pattern_2>.*$\|^.*<pattern_2>.*<pattern_1>.*$' input 
>header1
<pattern_1>CGGCGGGCAGATGGCCACCAACAACCAGAGCTCCCTGGCCGGGCCTCTTTTCCTGACGGCCGCCCCCACTGCCCCCACGACCGGCCCGTACAAC<pattern_2>
>header2
<pattern_1>CGGCGGGCAGATGGCCACCAACAACCAGAGCTCCCTGGCCTGCAATCACTACTCGTGTTTTGCCACCACTGCCCCCACGACCGGCACGTACAAC<pattern_2>
>header2b
<pattern_2>CGGCGGGCAGATGGCCACCAACAACCAGAGCTCCCTGGCCTGCAATCACTACTCGTGTTTTGCCACCACTGCCCCCACGACCGGCACGTACAAC<pattern_1>
0 голосов
/ 07 декабря 2018
$ grep -A 1 header[12] file
>header1
<pattern_1>CGGCGGGCAGATGGCCACCAACAACCAGAGCTCCCTGGCCGGGCCTCTTTTCCTGACGGCCGCCCCCACTGCCCCCACGACCGGCCCGTACAAC<pattern_2>
>header2
<pattern_1>CGGCGGGCAGATGGCCACCAACAACCAGAGCTCCCTGGCCTGCAATCACTACTCGTGTTTTGCCACCACTGCCCCCACGACCGGCACGTACAAC<pattern_2>

man grep:

   -A NUM, --after-context=NUM
          Print  NUM  lines  of  trailing  context  after  matching lines.
          Places  a  line  containing  a  group  separator  (--)   between
          contiguous  groups  of  matches.  With the -o or --only-matching
          option, this has no effect and a warning is given.

   -B NUM, --before-context=NUM
          Print NUM  lines  of  leading  context  before  matching  lines.
          Places   a  line  containing  a  group  separator  (--)  between
          contiguous groups of matches.  With the  -o  or  --only-matching
          option, this has no effect and a warning is given.

grep -B 1 pattern_[12] также может работать, но у вас есть несколько pattern_1 с в данных выборки, так что ... не в этот раз.

0 голосов
/ 07 декабря 2018

Вы можете легко сделать это с помощью awk следующим образом:

awk '/^>/{h=$0;next}
     /<pattern_1>/&&/<pattern_2>/{print h;print}' input.fasta > output.fasta

А вот решение sed, которое также дает желаемый результат:

sed -n '/^>/{N;/<pattern_1>/{/<pattern_2>/p}}' input.fasta > output.fasta

Если этовероятно, что существуют многострочные записи, вы можете использовать это:

awk -v pat1='<pattern_1>' -v pat2='<pattern_2>' '
/^>/ {r=$0;p=0;next}
!p {r=r ORS $0;if(chk()){print r;p=1};next}
p

function chk(   tmp){
    tmp=gensub(/\n/,"","g",r)
    return (tmp~pat1&&tmp~pat2)
}' input.fasta > output.fasta
0 голосов
/ 07 декабря 2018

Если вы хотите, чтобы grep печатал строки вокруг совпадения, используйте флаг -B для строк до, -A для строк после и -C как до, так и после совпадения.

В вашем случае, grep -B 1, похоже, это сделает работу.

...