Sed Every X строк, GREP между Y линий - PullRequest
       5

Sed Every X строк, GREP между Y линий

0 голосов
/ 20 сентября 2018

У меня есть файл, который в основном содержит расположения значений, как представлено ниже (я пронумеровал строки.)

! MATCH       1
!             2
HIT           3
NUM     1     4
VAL A  82     5
LEU A 144     6
ALA A 154     7
VAL A 333     8
ALA A 334     9
PHE A 372     10
END           11
!             12

Я пытаюсь создать файл, который содержит все экземпляры, в которых эти блоки значенийсодержать PHE в строке 10, как указано выше (в отличие от ALA или VAL и т. д.).

краткий пример нескольких блоков значений в файле:

! MATCH 
!
HIT 
NUM     1
VAL A 184
PHE A 209
END 
!
! MATCH
!
HIT
NUM     1
LEU A 296
ILE A 321
END 
!
! MATCH
!
HIT 
NUM     1
LEU A 296
PHE A 321
END 
!

Myкод, пытающийся сделать это:

sed -n '23~12p' file.txt | grep -B 9 -A 2 PHE > newfile.txt

По сути, начиная со строки 23, пропускайте каждые 12 строк (чтобы посмотреть только строку 10 блока значений), затем выполняйте grep предыдущих 9 строк и последующих2, если PHE присутствует в строке 10 блока значений.

Однако, как я уверен, вы можете сказать, приведенный выше код выводит только предыдущие строки в выводе sed.

sed -n '23~12p' file.txt | grep -B 9 -A 2 PHE file.txt > newfile.txt

Но если я добавлю файл (file.txt) для grep, он проигнорирует вывод sed и вместо этого отобразит предыдущие строки, даже если PHE не находится в десятой строке блока значений.

IE:

ILE A 222
END
!
! MATCH
!
HIT
NUM     1
ILE A 605
ILE A 620
PHE A 644   <--- What grep is matching
VAL A 633
ALA A 634

Я немного запутался, какw, чтобы написать этот скрипт для поиска PHE в позиции, которую я ищу (позиция 10), ища его каждые 12 строк и вычеркивая весь блок значений (предыдущие 9 строк и последующие 2 строки), только если PHEнашел в позиции 10.

Буду рад любым советам!Спасибо!

Ответы [ 4 ]

0 голосов
/ 21 сентября 2018

Это может работать для вас (GNU sed):

sed -n '14~12{h;b};H;23~12{/^PHE/!{x;z;x}};25~12{x;/^\n/!p;x}' file

Установите опцию, подобную grep -n.Начиная с 14-й строки и далее по модулю 12, установите пространство удержания для текущей строки и выйдите из сценария sed.Для всех остальных строк добавьте текущую строку в область удержания.В строке 23 и по модулю 12 после этого проверьте текущую строку, чтобы начать PHE, и если не очистить пространство удержания.В строке 25 и по модулю 12 после этого проверьте область удержания и, если она не начинается с новой строки, выведите все 12 строк в области удержания.

NB Если в строке 23 и по модулю 12 и после этого текущая строка не начинается PHE удержание очищается и добавляются последующие строки.К добавленным строкам добавляется новая строка, поэтому, если пробел начинается с новой строки, проверка на PHE не удалась, и эти строки можно отбросить.

Альтернатива:

sed -r '1,13d;:a;N;s/[^\n]*/&/12;Ta;/^([^\n]*\n){9}PHE/p;d' file

Удалить первые 13 строк.Соберите 12 строк и напечатайте их, если начинается 10-я строка PHE.

0 голосов
/ 21 сентября 2018

Похоже, это то, что вы пытаетесь сделать:

$ awk '
    { recLine = NR%8 }
    { rec = (recLine==1 ? "" : rec ORS) $0 }
    recLine==6 { f = /PHE/ }
    (recLine==0) && f { print rec }
' file
! MATCH
!
HIT
NUM     1
VAL A 184
PHE A 209
END
!
! MATCH
!
HIT
NUM     1
LEU A 296
PHE A 321
END
!

Просто измените 8 на 12 и 6 на 10 для ваших реальных данных.

0 голосов
/ 21 сентября 2018

Вот легко понимаемый и расширяемый скрипт.

#!/usr/bin/env perl
use strict;
my $matchNum=0;
my @match;
while (<STDIN>) {
  chomp;
  if (/^! MATCH$/) {
    @match and checkMatch(\@match, \$matchNum);
    @match=($_);
  } else { push @match, $_ }
}
@match and checkMatch(\@match, \$matchNum);

sub checkMatch {
  my ($matchAR, $matchNumSR) = @_;
  ++$$matchNumSR;
  if ( $matchAR->[9] =~ /^PHE/ ) {
    print "Match $$matchNumSR = $matchAR->[9]\n";
  }
}
0 голосов
/ 21 сентября 2018

Предполагая, что блоки разделены пустой строкой

perl -00 -wne'print if (split /\n/)[9] =~ /^PHE/' data.txt

См. perlrun для параметров командной строки.Здесь -00 разбивает ввод в абзацах, а затем каждый из них доступен программе под '' в специальной переменной $_.То есть split на новой строке, а десятая строка проверяется с помощью регулярного выражения, начинается ли она с PHE.Если да, мы печатаем весь блок.


Выясняется, что нет выделенных разделителей блоков;блоки просто идут один за другим, каждый начинается со строки ! MATCH и заканчивается строкой !.

Тогда вышеприведенное не может легко сохранить целые блоки после фильтрации, поскольку $/ из !, который можно установить с помощью переключателя -0\x21, приведет к ложным входным записям.Вместо этого обрабатывайте построчно.

Использование образца данных, добавленного в обновление вопроса

perl -ne'
    if (/^\! MATCH/ or eof) { $b[5]=~/^PHE/ and print for @b; @b=() };
    push @b, $_
' data.txt

Каждая строка добавляется в буфер (или «блок») @b.Строки, начинающиеся с ! MATCH, начинают новый блок, поэтому выведите предыдущий, если его шестая строка начинается с PHE (в реальных данных $b[9]), и очистите буфер для следующего блока.

The eof необходимо, чтобы сделать это и в конце ввода, для последнего блока / буфера.

Могу ли я предложить ввести пустую строку между записями при записи этого файла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...