awk NR == FNR для командного синтаксиса - PullRequest
0 голосов
/ 18 декабря 2018

У меня проблемы с использованием awk NR==FNR для возврата интересующих строк из входного файла .fastq.

У меня есть следующий пример входного файла с именем example.fastq

@SRR1111111.1 1/1
CTGGANAAGTGAAATAATATAAATTTTTCCACTATTGAATAAAAGCAACTTAAATTTTCTAAGTCG
+
AAAAA#EEEEEEEEEEEEEEEEEEEEEEEAEEEEEEEEEEEEEEEEEEEEEEEEEA<AAEEEEE<6
@SRR1111111.2 2/1
CTATANTATTCTATATTTATTCTAGATAAAAGCATTCTATATTTAGCATATGTCTAGCAAAAAAAA
+
AAAAA#EE6EEEEEEEEEEEEAAEEAEEEEEEEEEEEE/EAE/EAE/EA/EAEAAAE//EEAEAA6
@SRR1111111.3 3/1
CTATANTATTGAAATAATAATGTAGATAAAACTATTGAATAACAGCAACTTAAATTTTCAATAAGA
+
AAAAA#EE6EEEEEEEEEEEEAAEEAEEEEEEEEEEEE/EAE/EAE/EA/EAEAAAE//EEAEAA6

Я пытаюсь извлечь группы из четырех строк, которые содержат интересующую строку, важно, чтобы приблизительные совпадения были разрешены, поэтому вместо grep нужно использовать agrep.Приведенный ниже пример работает.

agrep -1 -n "GAAATAATA" example.fastq | awk -F: 'NR==FNR{for(i=($1-1);i<=($1+2);i++)a[i];next}FNR in a' - example.fastq

Приведенная выше команда создает следующий правильный вывод.

@SRR1111111.1 1/1
CTGGANAAGTGAAATAATATAAATTTTTCCACTATTGAATAAAAGCAACTTAAATTTTCTAAGTCG
+
AAAAA#EEEEEEEEEEEEEEEEEEEEEEEAEEEEEEEEEEEEEEEEEEEEEEEEEA<AAEEEEE<6
@SRR1111111.3 3/1
CTATANTATTGAAATAATAATGTAGATAAAACTATTGAATAACAGCAACTTAAATTTTCAATAAGA
+
AAAAA#EE6EEEEEEEEEEEEAAEEAEEEEEEEEEEEE/EAE/EAE/EA/EAEAAAE//EEAEAA6

Однако, если я использую последовательность, не содержащуюся во второй строке, эта команда по-прежнему печатает верхнюю частьдве строки, как в следующем примере.

agrep -1 -n "TAGATAAAACT" example.fastq | awk -F: 'NR==FNR{for(i=($1-1);i<=($1+2);i++)a[i];next}FNR in a' - example.fastq

@SRR1111111.1 1/1
CTGGANAAGTGAAATAATATAAATTTTTCCACTATTGAATAAAAGCAACTTAAATTTTCTAAGTCG
@SRR1111111.3 3/1
CTATANTATTGAAATAATAATGTAGATAAAACTATTGAATAACAGCAACTTAAATTTTCAATAAGA
+
AAAAA#EE6EEEEEEEEEEEEAAEEAEEEEEEEEEEEE/EAE/EAE/EA/EAEAAAE//EEAEAA6

Спасибо за помощь в понимании поведения этой команды awk.

Ответы [ 3 ]

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

Вы можете использовать это agrep + awk решение:

srch() {
   awk -F ': ' 'NR==FNR {
      a[$1] = 1
      next
   }
   a[FNR] {
      print p
      print
      for (i=0; i<2 && getline > 0; i++)
         print
   }
   {
      p=$0
   }' <(agrep -1 -n "$2" "$1") "$1"
}

Затем запустите его как:

srch file 'GAAATAATA'

@SRR1111111.1 1/1
CTGGANAAGTGAAATAATATAAATTTTTCCACTATTGAATAAAAGCAACTTAAATTTTCTAAGTCG
+
AAAAA#EEEEEEEEEEEEEEEEEEEEEEEAEEEEEEEEEEEEEEEEEEEEEEEEEA<AAEEEEE<6
@SRR1111111.3 3/1
CTATANTATTGAAATAATAATGTAGATAAAACTATTGAATAACAGCAACTTAAATTTTCAATAAGA
+
AAAAA#EE6EEEEEEEEEEEEAAEEAEEEEEEEEEEEE/EAE/EAE/EA/EAEAAAE//EEAEAA6

и это:

srch file 'TAGATAAAACT

@SRR1111111.3 3/1
CTATANTATTGAAATAATAATGTAGATAAAACTATTGAATAACAGCAACTTAAATTTTCAATAAGA
+
AAAAA#EE6EEEEEEEEEEEEAAEEAEEEEEEEEEEEE/EAE/EAE/EA/EAEAAAE//EEAEAA6'
0 голосов
/ 18 декабря 2018

с определением разделителя записей (GNU awk)

$ awk -v RS='(^|\n)@' '/GAAATAATA/{printf "%s", rt $0} {rt=RT}' file

@SRR1111111.1 1/1
CTGGANAAGTGAAATAATATAAATTTTTCCACTATTGAATAAAAGCAACTTAAATTTTCTAAGTCG
+
AAAAA#EEEEEEEEEEEEEEEEEEEEEEEAEEEEEEEEEEEEEEEEEEEEEEEEEA<AAEEEEE<6
@SRR1111111.3 3/1
CTATANTATTGAAATAATAATGTAGATAAAACTATTGAATAACAGCAACTTAAATTTTCAATAAGA
+
AAAAA#EE6EEEEEEEEEEEEAAEEAEEEEEEEEEEEE/EAE/EAE/EA/EAEAAAE//EEAEAA6
0 голосов
/ 18 декабря 2018

В вашем вводе нет двоеточий (:), поэтому $1 относится ко всей строке, а ($1-1) & ($2+2) будут -1 и 2 соответственно, что означает ваш for цикл всегда будет выполняться ровно четыре раза (для значений i, равных -1, 0, 1, затем 2).

Внутри цикла for вы 'чтобы убедиться, что a[i] существует (это a[-1], a[0], a[1] и a[2]).

В последней части вашего кода печатается проверяемая строка в это время (но неиз первого файла благодаря next в предыдущем разделе) всякий раз, когда массив a содержит запись для номера строки этого файла.Поэтому он печатает строки 1 и 2 из каждого ввода (поскольку a[FNR] существует для FNR, равного 1 или 2).

Поскольку вам нужен приблизительный ответ и, следовательно, необходимо использовать agrep, идеяпредложенный ответ Джеймса Брауна на ваш другой вопрос имеет смысл, но его реализация (как рассмотрено выше) - нет.

В следующем решении хиты agrep используются в качестве сигналов для окружающих строкпечатать вместе с попаданиями (agrep не поддерживает строки контекста, такие как grep * -A NUM и -B num, иначе мы могли бы сделать agrep -A1 -B2 -1 -n PATTERN example.fastq для более простого ответа).

agrep -1 "GAAATAATA" example.fastq | awk '
  NR == FNR { agrep_hit[$0] = 1; next }
  agrep_hit[$0] { print last_line; i = 1 }       
  0 < i && i < 4 { i++; print } 
  { last_line = $0 }
' - example.fastq

Это проверяет входной файл дважды.Первый раз использует agrep для нахождения приблизительного соответствия шаблону, а второй использует awk для получения запрошенных строк контекста.

Когда общий номер строки в awk (NR) равенномер строки локального файла (FNR), это означает, что мы проверяем первый ввод (-, стандартный ввод, который является выводом agrep).Мы сохраняем приблизительные совпадения паттернов в ассоциативном массиве для последующего использования, а затем переходим на следующую строку с next (поэтому остальные команды awk работают только на более поздних входах).

Поскольку вам нужнопредыдущая строка, мы должны напечатать это явно.Последняя строка кода awk сохраняет текущую строку как last_line, поэтому мы можем получить ее позже.На строке, которая была выведена с помощью agrep (и, таким образом, сохранена в нашем массиве), мы печатаем сохраненную last_line и устанавливаем итератор i на 1.

Когда i равен 1, 2 или 3, мы увеличиваем его и печатаем текущую строку.Это печатает соответствующую строку, а затем еще две для контекста.

...