Обработка файлов FASTQ на основе длины пары сопряжений

Следующие файлы представляют собой два сопряжения файла fastq с парным концом, я хочу разделить каждый файл fastq в зависимости от их длины.

mate1.fq:

@SRR127.1
TGGTTATGATGTTTGTGTAGGAATAGAAATTTTGATTAAGATATTAGTGAAATTTGAATGTAGTTTATTTGGAAGTTATGGAGAGTTTATATTGTATTTATGTTTATTGTTGTAGATTTATATTTATGTGTATATATTAGTTTTTTTGTGT
+
ABAAAF4FFFFFGGGGGGFFGGFGHGFGHHHHHGGCFFGHHHHH5FDBED55DGGFEGFHHHGBHDDHHHFF3AB3FFG5CBGBEF5BD5DGFEGHFAGAFEDGHGFHHGHGEFFGFGGHFEGHHFHGBEBGHHHHGHBHHFHHGGFGHH2
@SRR127.2
TATGGTAAGAAAATTGAAAATTATAAAAAATGAAAAATGTTTATTTGATGATTTGAAAAATGATGAAATTATTGAAAAATGTGAAAAATGAGAAATGTATATTGTAGGATTTGGAATATGGTGAGATAAATGAAAATTATAGTAAATG
+
AABAA5@D4@5CFFCA55FFGGHDGFHFFCC45DGFA2FA5DD55AAAA55DDBDEDDBGGFF5BA5DDABF5D5B5FF1ADFB5EDGHFG5@BFBD55D5FFB@@5@GBGEFBGHHGB@DBBFHFBDG3B43FFH@FGFHH?FHHHH

mate2.fq:

@SRR127.1
ACCTATAAAAAAACCATATCAATAACTATAAAATCTTTATAAAATCCCACCCAATTAAAAAAAAATAAATTAATACATATAAAACCTTAAACACATAAAACATAATCACATACTATATAAACAATTACTATCACTACTAAACACCTAATA
+
>AA?AF13B@D@1EFCGGGFFG3EBGHHHBB2FGHHGHGFDGHHDFEGFHGGGHG1FFF1GGCGGGBGHHHHHFHHHHFHEGGFHF0BD1FGHHAGEGHFHHHFGGFHHGHHHFHHGGFHBGHFED1FBGFGFHDGHGHFGG1GB0GFHH
@SRR127.2
CTATTTCTCATTTTTTTATAATTTTCAATTCTCTTACCATATTCCACATCCTACACTAAACATTTCTAAATTTTCCACCTTTTTCTATTTTTCTCACCATATTTCATATCCTAAAAAACATATTCCTCATTTACTATAATTTTCAATTATC
+
11>>AFFDFF3@FFF?EFFGFBGHFDFA33D2FF2GGHFE12DD221AF1F1E1BG1GGBFBGGEGHDAABGAGDFABGG1BBDF12A2@2BG@2@DEFFF2B2@2222BB2211FGEE/11@22B2>1B22F2>GBGBD22BGD2>2B22

Я написал следующий код, чтобы сделать это, но я получаю странную ошибку только для второго файла (mate2.fq), хотя оба они также имеют чтение 151 bp.

#!/usr/bin/perl

use strict;
use warnings;

my @fh;

my $file_name = $ARGV[0];
my $infile    = $ARGV[1];

#convert every 4-line fastq to 1-line
open(FH, "cat '$infile' | awk '{printf \"%s%s\",\$0,(NR%4?FS:RS)}' | ");

while (<FH>) {
  chomp;

  my @line = split(/\s+/, $_);
  my $len  = length($line[1]);

  if ($len >= 100) {

    #print $len,"\n",$_,"\n";
    push @fh, $len;

    if (not defined $fh[$len]) {
      open $fh[$len], '>', "$file_name\_$len";
    }
    print { $fh[$len] } (join("\n", @line), "\n");
  }

}

Ошибка:

Can't use string ("151") as a symbol ref while "strict refs" in use at

Как я могу обработать эти файлы?


person Tahmtan Ebrahimi    schedule 01.05.2015    source источник
comment
push @fh, $len; не имеет смысла, поскольку вы сохраняете простой скаляр в массиве, зарезервированном для файловых дескрипторов.   -  person mpapec    schedule 01.05.2015
comment
Спасибо. Я просто удалил его и работает!   -  person Tahmtan Ebrahimi    schedule 01.05.2015
comment
@TahmtanEbrahimi Я изменил заголовок вашего сообщения, чтобы сделать его более содержательным и общим для будущих поисков, и сохранил сообщение об ошибке в теле теста. Как правило, заголовки не должны быть слишком длинными или повторять определенные сообщения об ошибках или код — вместо этого они должны быть в теле вашего сообщения. Пожалуйста, отредактируйте заголовок, чтобы биоинформатикам было понятно, если я допустил ошибку в формулировке.   -  person G. Cito    schedule 01.05.2015
comment
Хотя вы не используете пакеты Bioperl напрямую, я добавил этот тег для релевантности. Некоторые из существующих скриптов BioPerl, включенных в дистрибутив BioPerl, могут оказаться полезными для этого или других аспектов вашей работы. .   -  person G. Cito    schedule 01.05.2015


Ответы (2)


Как вы прочитали, ваша проблема связана с ложным push, который добавляет целочисленное значение в конец массива @fh. Я предполагаю, что вы стремились расширить массив, чтобы он был достаточно длинным, чтобы добавить новый дескриптор файла. Вы можете сделать это, назначив $#fh, поэтому вы должны написать $#fh = $len if $#fh < $len; однако в этом нет необходимости, потому что Perl будет автоматически расширять массивы для вас, когда вы просто присваиваете элемент за пределами конца массива.

У меня есть пара замечаний по вашей программе, которые, я надеюсь, будут вам полезны.

  • Ненужно и расточительно раскошеливаться на команду awk. Perl вполне способен делать все то же, что и awk.

  • Если вы обнаружите, что пишете split /\s+/, $_, то почти наверняка имеете в виду только split: поведение по умолчанию — split ' ', $_. Если вы используете /\s+/ в качестве шаблона и в строке, которую вы разбиваете, есть начальные пробелы, то split вернет пустую строку в качестве первого элемента в списке полей. Если вместо этого вы используете ' ' (буквальный одиночный пробел, а не шаблон / /), этого не произойдет. По сути, split ' ' эквивалентно /\S+/g.

  • При интерполяции значений переменных в строке, как правило, лучше помещать идентификаторы в фигурные скобки, если есть следующий символ, который может быть частью идентификатора. Итак, "${file_name}_$len" вместо "$file_name\_$len"

Вот как я бы написал ваш код. Он накапливает входные записи в $line до тех пор, пока не будут добавлены четыре записи, а затем обрабатывает эту строку, как и раньше.

#!/usr/bin/perl

use strict;
use warnings;

my ($file_name, $infile) = @ARGV;

open my $in_fh, '<', $infile or die $!;
my $line;

my @fh;
while ( <$in_fh> ) {
  chomp;
  $line .= $_;

  if ( $. % 4 == 0 or eof ) {

    my @line = split ' ', $line;
    my $len  = length $line[1];
    next if $len < 100;

    open $fh[$len], '>', "${file_name}_$len" unless $fh[$len];
    print { $fh[$len] } "$_\n" for @line;

    $line = undef;
  }
}
person Borodin    schedule 01.05.2015
comment
Огромное спасибо - person Tahmtan Ebrahimi; 01.05.2015
comment
Совет: я сомневаюсь, что большинство людей знают, что eof и eof() разные, не говоря уже о том, что каждый из них делает. Лучше всего использовать eof($in_fh). - person ikegami; 01.05.2015
comment
@ikegami: я думаю, этого достаточно, чтобы ваш комментарий рассказал свою собственную историю. Для меня это ошибка дизайна, так как даже eof() и eof ARGV разные - person Borodin; 01.05.2015
comment
Конечно, это плохой дизайн. - person ikegami; 01.05.2015

Эта ошибка конкретно означает, что вы делаете что-то, что ожидает ссылку, но не получает ее.

Линия:

print {$fh[$len]} (join("\n",@line),"\n");

Явно печатает в дескриптор файла - из того, что выглядит как список дескрипторов файлов с именем @fh.

Эта строка:

push @fh, $len;

Будет вставлять числовое значение в этот список. (Предположительно $line[1] имеет длину 151 символ). Итак, вы на самом деле пытаетесь:

 print {151} (join("\n",@line),"\n");

Что, надеюсь, довольно очевидно - просто не сработает. Похоже, вы пытаетесь открыть дескриптор файла и вставить его в массив:

open $fh[$len], '>', "$file_name\_$len";

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

Где вы могли бы вместо этого:

#further up:
my %fh; 


#and then
open ( $fh{$len}, ">", "$file_name\_$len" ) or warn $!; 

Не забудьте закрыть дескрипторы файлов в конце:

foreach my $key ( keys %fh ) {
   close ( $fh{$key} );
}

Я бы также предложил, а не:

open( FH, "cat '$infile' | awk '{printf \"%s%s\",\$0,(NR%4?FS:RS)}' | " );

Вам, вероятно, лучше обрабатывать это в perl, поскольку все, что вы делаете, это анализируете файл с помощью внешнего двоичного файла. (И используйте лексические дескрипторы файлов: `open ( $input, "-|,"cat '$infile' | awk '{printf \"%s%s\",\$0,(NR%4?FS:RS)}' " ) или предупредить $!; )

person Sobrique    schedule 01.05.2015