Мои познания в Perl невелики, но, поскольку никто еще не дал ответа на Perl, я попробую.
Передайте ваши данные в виде файла, и он напечатает строки, разделенные табуляцией, с тремя значениями в строке:
perl -e 'while (<>) { $s .= $_; } chomp $s; @arr = split(/\n{2,}/, $s); foreach my $a(@arr) { $a =~ s/Filename: ([^\n]*)\nType: ([^\n]*)\nSize: ([^\n]*)\n.*/$1\t$2\t$3\n/ || next; print "$a"; } ' infile
Результат:
XXXXX XXX XXXX
YYYYY YYY YYYY
Это немного грубо, но работает, разбивая ввод на абзацы/блоки и затем применяет ваше многострочное регулярное выражение к каждому.
Подробности...
while (<>) { $s .= $_; }
— Объединить ввод в одну строку.chomp $s
— удалить завершающую новую строку из строки.@arr = split(/\n{2,}/, $s)
— Разделить строку на последовательные
новые строки. Это разбивает его на абзацы/блоки. Храните блоки в массиве.foreach my $a(@arr)
— Перебирать каждый элемент массива (блок). Следующие две строки кода применяются к каждому блоку.$a =~ s/Имя файла: ([^\n]*)\nТип: ([^\n]*)\nРазмер: ([^\n]*)\n.*/$1\t$2 \t$3\n/ || next
— извлечь значения из трех интересующих полей.Если подстановки не происходит (это означает, что регулярное выражение не соответствует, например, из-за отсутствия значения), пропустите этот блок и перейдите к следующему.print "$a"
- Печать
результат подстановки: три значения, разделенные табуляцией.Опять же, я мало пользуюсь Perl, поэтому, вероятно, есть более элегантные решения.
IMHO было бы более естественно использовать пустую строку в качестве разделителя записей. В этом «режиме абзаца» awk включает символы новой строки в качестве разделителей полей, поэтому в вашем случае каждая строка записи становится полем. Затем вы можете удалить первое поле, присвоив ему пустую строку; у этого есть хороший побочный эффект переоценки всей записи с заданным разделителем выходных полей: при установке этого значения также на пустую строку, остальные поля объединяются. Затем вы можете просто распечатать длину записи.
awk 'BEGIN {RS="";OFS=""} NR==1 {$1=""; print length}' species_gene
Тестирование с заданными вами входными данными
$ awk 'BEGIN {RS="";OFS=""} NR==1 {$1=""; print length}' species_gene
160
length
- это не только переменная в Awk, но и функция:
$ awk 'BEGIN {RS=">"} NR==2 {print length($2) + length($3)}' species_gene
160
Вот и все: сложите длины двух полей, а не используйте длину всей записи.
Короче:
$ awk 'BEGIN {RS=">"} NR==2 {print length($2 $3)}' species_gene
160
Одинаково долго:
$ awk 'BEGIN {RS=">"} NR==2 && $0 = length($2 $3)' species_gene
160
Возможное незначительное улучшение { {1}} за ваше улучшение до ответа Steeldriver :
awk -vRS=">" -vOFS="" '$1=="genus_1_species_1" {$1=""; print length;}' species_gene
-vRS = ">"
эквивалентно BEGIN {RS = " > "}
,
и аналогично с -vOFS =" "
.
Мой вклад состоит в том, что эта версия позволяет вам указывать
заголовок записи, длина которой,
, чтобы вам не приходилось подсчитывать записи.