1

以下文件是双端 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

#!/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

如何处理这些文件?

4

2 回答 2

6

如您所读,您的问题是因为在数组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;
  }
}
于 2015-05-01T11:32:01.623 回答
5

这个错误的具体含义是你正在做一些需要参考的事情,但它没有得到参考。

该行:

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)}' " ) 或警告 $!; )

于 2015-05-01T10:08:30.077 回答