Perl System()中的嵌套引号



我正在尝试修改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 tblastnn";

我试图用以下内容替换系统(" 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 tblastnn";

这用GNU Parallel代替了普通的TBLASTX程序,该程序将TBLASTX命令管道。在bash中运行上述命令(用实际文件替换温度输入)可以很好地工作,但是当perl脚本尝试执行它时,错误日志(用于tblastx)表示,在sseqids之后,它终止了太早。如果您在bash中没有逃生字符的情况下运行相同的命令,则会发生同样的错误。

因此,我假设错误是由于" 7 sequids sstart ..."围绕的单个报价造成的。我不确定如何在perl中正确执行嵌套引号。我以为我这样做是正确的,因为它可以通过bash工作,但不能通过perl脚本进行操作。我看了很多perl文档,一切都说逃脱字符应该用引号或双引号起作用。

有人可以提供有关为什么没有处理引号的输入?

这里的问题几乎可以肯定是报价插值。每次"外壳"时,您都会解开另一层的报价。报价中的作用是一个问题,即您是在执行双引号 "- interpolate还是单个报价 ',然后将其视为文字,然后再传递到 shell shell。

有关Perl的引用,请参见perlop。我建议您尝试组装这样的命令:

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 );

(显然要检查您的"命令"在将其传递给系统之前是否看起来像)

但是我可以建议另一种方法吗?怎么样,而不是嵌入catparallel,可以在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 tblastnn";
    $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具有更大的范围和灵活性,但要"炮击"来做事。

引用是bit子。引用两次是bit子。

首先检查您认为正在运行的事情实际上正在运行。在这里,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 tblastnn";

如果您要重新读取$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 tblastnn";
while(<$fh>) { ... }
close $fh;

将避免创建临时文件,如果$TMP可以由攻击者编写,这也可以插入安全孔。作为额外的奖励,您将较早获取数据,因为您不必等到每个工作完成。