Обработка файлов 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 б.п.
#!/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
Как я могу обработать эти файлы?
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;
}
}
Что конкретно означает эта ошибка, так это то, что вы делаете что-то, что ожидает ссылку, но не получает ее.
Линия:
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)}'") или предупредите $!;)