Как извлечь несколько битов информации, которые появляются в разных строках одного и того же текстового файла

8

Я пытаюсь извлечь идентификатор последовательности и номер кластера, которые встречаются в разных строках в одном и том же текстовом файле.

Вход выглядит как

>Cluster 72
0   319aa, >O311_01007... *
>Cluster 73
0   318aa, >1494_00753... *
1   318aa, >1621_00002... at 99.69%
2   318aa, >1622_00575... at 99.37%
3   318aa, >1633_00422... at 99.37%
4   318aa, >O136_00307... at 99.69%
>Cluster 74
0   318aa, >O139_01028... *
1   318aa, >O142_00961... at 99.69%
>Cluster 75
0   318aa, >O300_00856... *

Желаемый результат - идентификатор последовательности в одном столбце и соответствующий номер кластера во втором.

>O311_01007  72
>1494_00753  73
>1621_00002  73
>1622_00575  73
>1633_00422  73
>O136_00307  73
>O139_01028  74
>O142_00961  74
>O300_00856  75

Может кто-нибудь помочь с этим?

Тим
источник
Всегда ли идентификатор последовательности будет трехмерным полем в строках, которые не начинаются с >? Также вас может заинтересовать наш родственный сайт, Биоинформатика .
Тердон

Ответы:

13

С awk:

awk -F '[. ]*' 'NF == 2 {id = $2; next} {print $3, id}' input-file
  • мы разделяем поля на пространства или периоды с -F '[. ]*'
  • со строками из двух полей ( >Clusterстроки), сохраните второе поле как идентификатор и перейдите к следующей строке
  • с другими строками выведите третье поле и сохраненный идентификатор
Мур
источник
Вместо того, чтобы указывать количество полей, лучше было бы явно искать $1 == ">Cluster"вместо NF == 2, в зависимости от того, что еще может быть в файле.
Монти Хардер
5

Вы можете использовать awkдля этого:

awk '/>Cluster/{
      c=$2;
      next
    }{
      print substr($3,2,length($3)-4), c
    }' file

Первый оператор блока захватывает идентификатор кластера. Второй оператор блока (по умолчанию) извлекает нужные данные и печатает их.

Олив
источник
Вам не нужно приводить " "аргументы print. Просто используйте запятую для разделения аргументов, и он будет использовать OFS, пространство по умолчанию, для разделения аргументов.
Муру
4

Вот альтернатива с Ruby в качестве однострочного:

ruby -ne 'case $_; when /^>Cluster (\d+)/;id = $1;when /, (>\w{4}_\w{5})\.\.\./;puts "#{$1} #{id}";end' input_file

или распределить по нескольким строкам:

ruby -ne 'case $_
when /^>Cluster (\d+)/
  id = $1
when /, (>\w{4}_\w{5})\.\.\./
  puts "#{$1} #{id}"
end' input_file

Я полагаю, что он более читабелен, чем awkверсия, если вы знаете Ruby и regexen. В качестве бонуса этот код может быть немного более надежным, чем просто разбиение строк, потому что он ищет окружающий текст.

Эрик Думинил
источник
1

Perl:

$ perl -ne 'if(/^>.*?(\d+)/){$n=$1;}else{ s/.*(>[^.]+).*/$1 $n/; print}' file 
>O311_01007 72
>1494_00753 73
>1621_00002 73
>1622_00575 73
>1633_00422 73
>O136_00307 73
>O139_01028 74
>O142_00961 74
>O300_00856 75

объяснение

  • perl -ne: прочитайте входной файл построчно ( -n) и примените скрипт, заданный -eдля каждой строки.
  • if(/^>.*?(\d+)/){$n=$1;}: если эта строка начинается с a >, найдите самый длинный отрезок чисел в конце строки и сохраните его как $n.
  • else{ s/.*(>[^.]+).*/$1 $n/; print: если строка не начинается с >, замените все с самым длинным отрезком не- .символов после a >( >[^.]+), то есть именем последовательности ( $1потому что мы захватили совпадение с регулярным выражением) и текущим значением $n.

Или для более похожего на awk подхода:

$ perl -lane 'if($#F==1){$n=$F[1]}else{$F[2]=~s/\.+$//; print "$F[2] $n"}' file 
>O311_01007 72
>1494_00753 73
>1621_00002 73
>1622_00575 73
>1633_00422 73
>O136_00307 73
>O139_01028 74
>O142_00961 74
>O300_00856 75

Это просто немного более громоздкий способ реализации той же основной идеи, что и различные awkподходы. Я включил это ради завершения и для поклонников Perl. Если вам нужно объяснение, просто используйте решения awk :).

terdon
источник