Як отримати декілька бітів інформації, що з’являються в різних рядках в одному текстовому файлі


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

Хтось може допомогти у цьому?


Чи завжди ідентифікатор послідовності буде 3D-полем, розділеним пробілом, на лініях, які не починаються >? Також вас може зацікавити наш сестринський сайт, Біоінформатика .
тердон

Відповіді:


13

З awk:

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

Замість того, щоб викреслювати кількість полів, краще буде чітко шукати $1 == ">Cluster"замість цього NF == 2, залежно від того, що ще може бути у файлі.
Monty Harder

5

Ви можете використовувати awkдля цього:

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

Перший оператор блоку - це захоплення ідентифікатора кластера. Другий оператор блоку (за замовчуванням) - це вилучення потрібних даних та друк.


Вам не потрібно наводити " "як аргумент print. Просто використовуйте кому для розділення аргументів, і вона використовуватиме OFS, пробіл за замовчуванням, для розділення аргументів.
муру

4

Ось альтернатива Рубі як однолінійному:

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;}: якщо цей рядок починається з а >, знайдіть найдовший розтяг чисел у кінці рядка та збережіть це як $n.
  • else{ s/.*(>[^.]+).*/$1 $n/; print: Якщо рядок не починається з >, замінити всі з найдовшим протяжністю непредставлених .символів слідуючи за >( >[^.]+), тобто ім'я послідовності ( $1тому що ми захопили матч регулярного виразу) і поточне значення $n.

Або для більш дивного підходу:

$ 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 :).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.