我试图修改perl脚本。以下是我要修改的部分:
原件:
system ("tblastn -db $BLASTDB -query $TMP/prot$$.fa \\
-word_size 6 -max_target_seqs 5 -seg yes -num_threads $THREADS -lcase_masking \\
-outfmt \"7 sseqid sstart send sframe bitscore qseqid\"\\
> $TMP/blast$$") && die "Can't run tblastn\n";
我正在尝试用以下内容替换系统(" tblastn ....."):
system ("cat $TMP/prot$$.fa | parallel --block 50k --recstart '>' --pipe \\ tblastn -db $BLASTDB -query - -word_size 6 -outfmt \'7 sseqid sstart send sframe bitscore qseqid\' -max_target_seqs 5 -seg yes -lcase_masking > $TMP/blast$$") && die "Can't run tblastn\n";
这用普通的tblastx程序取代了GNU parallel,它管理了tblastx命令。在bash中运行上面的命令(用实际文件替换临时输入)可以很好地工作,但是当perl脚本尝试执行它时,错误日志(对于tblastx)说它在sseqids之后很快就终止了。如果在bash中运行没有转义字符的相同命令,则会发生同样的错误。
由于这个原因,我假设错误是由于" 7 ssequids sstart周围的单引号......"没有被正确解析。我不确定如何在perl中正确执行嵌套引号。我以为我做得对,因为它通过bash而不是通过perl脚本工作。我查看了很多perl文档,并且所有内容都说转义字符\应该使用引号或双引号。但是对于我的实例它不起作用。
有人可以提供关于为什么没有处理报价的输入吗?
答案 0 :(得分:1)
这里的问题几乎可以肯定是引用插值。每次你掏空'你打开另一层报价。它在引号内的作用是一个问题,即你是否正在进行双引号"
- 它是插值,还是单引号'
然后将其作为文字处理,然后传递到下一个 shell。
请参阅perlop
了解perl的引用方式。
我建议你尝试组装一个这样的命令:
my $parallel = q{parallel --block 50k --recstart '>' --pipe};
my $outfmt = q{'7 sseqid sstart send sframe bitscore qseqid'};
print $parallel,"\n";
print $outfmt,"\n";
my $command = "cat $TMP/prot$$.fa | $parallel \\ tblastn -db $BLASTDB -query - -word_size 6 -outfmt $outfmt -max_target_seqs 5 -seg yes -lcase_masking > $TMP/blast$$";
print $command;
system ( $command );
(显然检查你的'命令在将它传递给系统之前看起来正确)
但我可以建议一种不同的方法吗?如果不是嵌入cat
和parallel
,您可以在perl
中本地执行此操作。
我已经知道我不熟悉你正在运行的命令,但它不是之类的东西:
#!/usr/bin/perl
use strict;
use warnings;
open( my $input, "<", "$TMP/prot$$.fa" ) or die $!;
my $fork_manager = Parallel::ForkManager->new($THREADS);
while ( my $line = <$input> ) {
$fork_manager->start and next;
chomp $line;
system(
"tblastn -db $BLASTDB -query $line \\
-word_size 6 -max_target_seqs 5 -seg yes -lcase_masking \\
-outfmt \"7 sseqid sstart send sframe bitscore qseqid\"\\
> $TMP/blast$$"
) && die "Can't run tblastn\n";
$fork_manager->finish;
}
close ( $input );
如果需要输出合并,我可能会切换到使用线程:
#!/usr/bin/perl
use strict;
use warnings;
use IPC::Open2;
use threads;
use Thread::Queue;
my $num_threads = 8;
my $work_q = Thread::Queue -> new();
my $results_q = Thread::Queue -> new();
sub worker {
open2 ( my $blast_out, my $blast_in, "tblastn -db $BLASTDB -query - -word_size 6 -outfmt '7 sseqid sstart send sframe bitscore qseqid' -max_target_seqs 5 -seg yes -lcase_masking");
while ( my $query = $work_q -> dequeue ) {
print {$blast_in} $query;
$results_q -> enqueue ( <$blast_out> ); #one line - you'll need something different for multi-line results.
}
close ( $blast_out );
close ( $blast_in );
}
sub collate_results {
open ( my $output, "$TMP/results.$$" ) or die $!;
while ( my $result = $results_q -> dequeue ) {
print {$output} $result,"\n";
}
close ( $output );
}
my @workers;
for (1..$num_threads) {
push ( @workers, threads -> create ( \&worker ) );
}
my $collator = threads -> create ( \&collate_results );
open( my $input, "<", "$TMP/prot$$.fa" ) or die $!;
while ( my $line = <$input> ) {
chomp $line;
$work_q -> enqueue ( $line );
}
close ( $input );
$work_q -> end;
foreach my $thr ( @workers ) {
$thr -> join();
}
$results_q -> end;
$collator -> join;
现在我很欣赏这些看起来有点复杂和复杂。但是他们更多的例子是如何将perl扩展到并行,因为通过这样做,你拥有比运行perl更多的范围和灵活性,但是&#39;炮轰&#39;做事。
答案 1 :(得分:1)
引用是一个婊子。引用两次是一个婊子。
首先检查您认为正在运行的内容是否正在运行。这里print STDERR
可以创造奇迹。
在你的情况下,我认为这将解决它:
my $TMP = $ENV{'TMP'};
my $BLASTDB = $ENV{'BLASTDB'};
my $cmd = qq{cat $TMP/prot$$.fa | parallel --block 50k --recstart '>' --pipe tblastn -db $BLASTDB -query - -word_size 6 -outfmt \\''7 sseqid sstart send sframe bitscore qseqid'\\' -max_target_seqs 5 -seg yes -lcase_masking > $TMP/blast$$};
print STDERR $cmd,"\n"; # Remove this when it works.
system($cmd) && die "Can't run tblastn\n";
如果您要重新阅读$TMP/blast$$
并将其删除,则可以改为:
my $TMP = $ENV{'TMP'};
my $BLASTDB = $ENV{'BLASTDB'};
open(my $fh, "-|", qq{cat $TMP/prot$$.fa | parallel --block 50k --recstart '>' --pipe tblastn -db $BLASTDB -query - -word_size 6 -outfmt \\''7 sseqid sstart send sframe bitscore qseqid'\\' -max_target_seqs 5 -seg yes -lcase_masking}) || die "Can't run tblastn\n";
while(<$fh>) { ... }
close $fh;
这将避免创建临时文件,如果攻击者可以写入$TMP
,这也会导致安全漏洞。作为额外的奖励,您将获得更早的数据,因为您不必等到每个工作都完成。