3

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 プログラムが、tblastx コマンドをパイプ処理する GNU 並列プログラムに置き換えられます。上記のコマンドを bash で実行すると (temp 入力を実際のファイルに置き換えて) は完全に機能しますが、perl スクリプトが実行しようとすると、エラー ログ (tblastx の場合) に、sseqids の後、すぐに終了したと表示されます。bash でエスケープ文字を使用せずに同じコマンドを実行すると、同じエラーが発生します。

このため、エラーは「7 ssequids sstart...」を囲む一重引用符が適切に解析されていないことが原因であると想定しています。perl でネストされた引用符を適切に行う方法がわかりません。それはbash経由では機能しますが、perlスクリプト経由では機能しないので、私はそれを正しくやっていると思いました。私はたくさんの perl ドキュメントを見ましたが、エスケープ文字 \ は引用符または二重引用符で動作するはずですが、私のインスタンスでは動作しません。

見積もりが処理されていない理由について誰かが意見を提供できますか?

4

2 に答える 2

1

ここでの問題は、ほぼ間違いなくクオート補間です。「シェルアウト」するたびに、引用符の別のレイヤーをアンラップします。引用符の中で何をするかは、二重引用符を使用しているかどうかの問題です"-補間するか、単一引用符を使用してから、次のシェル'に渡す前にそれをリテラルとして扱います。

perlopperl が引用を行う方法については、を参照してください。次のようなコマンドを組み立ててみることをお勧めします。

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 を実行するよりもはるかに多くの範囲と柔軟性が得られるからです。

于 2015-05-06T08:49:22.857 に答える