2017-12-04 11 views
1

配列の配列をサブルーチンに渡すサブルーチンを作成しようとしているので、異なるディレクトリで並列に実行することができます。配列の配列をPerlのサブルーチンに渡す

基本的に、それぞれの最初のインデックスは、各コマンド - ディレクトリのペアです。 2番目のインデックスには、ディレクトリとコマンドその2つの変数があります。例えば

my @commands; 
$commands[0][0] = 'tmp1';#directory 
$commands[0][1] = 'echo "ave Maria" > avemaria.txt';#command 

ただし、Iはサブルーチン内のデータを参照する方法を見つけ出すことができない、私は多くの異なる場所に考えることができ、「[] {}」の全ての可能な組み合わせを試してみました。私はhttps://perldoc.perl.org/perldsc.htmlでperlのドキュメントを読んだことがありますが、ここにどのように当てはまるのか分かりません。

#!/usr/bin/env perl 

use strict; use warnings; use Cwd; 
my $TOP_DIRECTORY = getcwd(); 
local $SIG{__WARN__} = sub {#kill the program if there are any warnings 
    my $message = shift; 
    my $fail_filename = "$TOP_DIRECTORY/$0.FAIL"; 
    open my $fh, '>', $fail_filename or die "Can't write $fail_filename: $!"; 
    printf $fh ("$message @ %s\n", getcwd()); 
    close $fh; 
    die "$message\n"; 
};#http://perlmaven.com/how-to-capture-and-save-warnings-in-perl 

sub execute { 
    my $command = shift; 
    print "Executing Command: $command\n"; 
    if (system($command) != 0) { 
     my $fail_filename = "$TOP_DIRECTORY/$0.fail"; 
     open my $fh, '>', $fail_filename or die "Can't write $fail_filename: $!"; 
     print $fh "$command failed.\n"; 
     close $fh; 
     print "$command failed.\n"; 
     die; 
    } 
} 

sub run_parallel { 
    my $command_array_reference = shift; 
    unless ((ref $command_array_reference) =~ m/ARRAY/) { 
     print "run_parallel requires an array reference as input.\n"; 
     die; 
    } 
    use Parallel::ForkManager; 
    my $manager = new Parallel::ForkManager(4); 
    my $START_DIRECTORY = getwd(); 
    foreach my $command (0..scalar @{ $command_array_reference }-1) { 
     $manager->start and next; 
     my $dir = @$command_array_reference[$command][0]; 
     chdir $dir or die "Can't chdir to $dir: $!"; 
     execute(@$command_array_reference[$command][1]); 
     chdir $START_DIRECTORY or die "Can't chdir to $START_DIRECTORY: $!"; 
     $manager->finish; 
    } 
    $manager->wait_all_children;#necessary after all lists 
} 

my @commands; 

$commands[0][0] = 'tmp1';#directory 
$commands[0][1] = 'echo "ave Maria" > aveMaria.txt';#command 

$commands[1][0] = 'tmp2';#directory 
$commands[1][1] = 'echo "IN HOC SIGNO VINCES" > xp.txt';#command 

run_parallel(\@commands); 

この特定の構成は、私は、サブルーチン内のディレクトリ・コマンドのペアを読むことができますどのようにエラー

[email protected]:~/Scripts$ perl parallelForkManager_dir.pl 
syntax error at parallelForkManager_dir.pl line 38, near "][" 
Global symbol "$dir" requires explicit package name at parallelForkManager_dir.pl line 39. 
Global symbol "$dir" requires explicit package name at parallelForkManager_dir.pl line 39. 
syntax error at parallelForkManager_dir.pl line 40, near "][" 
Execution of parallelForkManager_dir.pl aborted due to compilation errors. 

を生成?

+3

あなたはいくつかのチュートリアルで学習しているようです。そのうちの1つはGaborのPerlMavenです。それは素晴らしいことです。しかし、今はあなたのスタイルが戦略を奪い、コードには多くの問題があります。必要ならば、[codereview]のPerlタグで自由に投稿することができます。誰かが見て、あなたにいくつかのコードスタイルのアドバイス、そしておそらくあなたの戦略について何かを与えるでしょう。また、エラーメッセージの読み取りを開始する必要があります。正確であることはプログラミングの大きな部分であり、通常はエラーが発生したときにメッセージが役に立ちます。 :) – simbabque

+3

私は** simbabque **が言ったことを支持します。私はあなたの* working *コードを[Code Review](https://codereview.stackexchange.com/)に投稿し、私たちがそれを批評できるようにすることで多くを学ぶと思います。私はしばしば自分の答えをOPのコードのレビューと結びつけますが、それは厳密には話題にはなりません。自分でレビューを求めるのがはるかに良いです。 – Borodin

+1

@Borodinそこに行く:https://codereview.stackexchange.com/q/182010/23233 – simbabque

答えて

1

データ構造について疑問がある場合は、Data::Dumperはあなたの友人です。

use Data::Dumper; 

# with your @commands 
print Dumper \@commands; 

これは

$VAR1 = [ 
     [ 
     'tmp1', 
     'echo "ave Maria" > aveMaria.txt' 
     ], 
     [ 
     'tmp2', 
     'echo "IN HOC SIGNO VINCES" > xp.txt' 
     ] 
    ]; 

は、今、私たちは内部の配列参照を持つ配列参照があることを知って印刷します。最初の参照レベルは、\@commandsのバックスラッシュです。配列への参照が作成されます。 2番目の参照はその内部の各配列refです。

Perlでは、配列内に配列を持つことはできず、配列への参照のみができます。あなたがそれらを割り当てる方法は間違いなく正しいものですが、おそらくあなたを混乱させるでしょう。

$commands[0][0] = 'tmp1'; 
$commands[0]->[0] = 'tmp1'; # equivalent 

->は逆参照演算子です。

my $command_array_reference = \@commands; 

値を取得するには、矢印を使用します。彼らは常に今、あなたのサブにあなたが持っている最初の

超えて参照されているので、それは、多次元データ構造のために必須ではありません。それらのほとんどを省略することができますが、最初のものは必須です。

my $dir = $command_array_reference->[0]->[0]; 
my $cmd = $command_array_reference->[0]->[1]; 

あなたは何$foo->[0]の内だが配列リファレンスであることをPerlを伝え、このような最初のレベル、逆参照、リストとして全体を取得したい場合:

my ($dir, $cmd) = @{ $command_array_reference->[0] }; 

I perlreftutperlref、おそらくperllolをご覧ください。

+0

私は['Data :: Dump'](https://metacpan.org/pod/Data::Dump)を好む。出力ははるかに読みやすく、 'dd'をエクスポートするので、' print Dumper \ @ commands'は 'dd \ @ commands'になります。唯一の欠点は、コアでないことです。 – Borodin

+0

私の編集は大丈夫ですか?私はタイプミスを修正してから 's/needed/required /'に行きました。なぜなら*必須*は絶対的なものであり、* need *は単なる生死のものかもしれないからです。 – Borodin

+0

@Borodinええ、それはいいです、ありがとう。私はあなたが知っている、あなたは私がデータ::プリンタを好むことを知っている。 ;)しかし、私は、すぐに使えるソリューションはここで問題ないと思いました。 – simbabque

関連する問題