2017-12-04 1 views
1

배열 배열을 서브 루틴으로 전달하여 명령을 다른 디렉토리에서 병렬로 실행할 수있는 서브 루틴을 만들려고합니다.배열 배열을 Perl에서 서브 루틴으로 전달

기본적으로 각 첫 번째 색인은 각 명령 - 디렉토리 쌍에 대한 것입니다. 두 번째 색인에는 디렉토리와 명령 자체라는 두 가지 변수가 있습니다. 예를 들어

그러나

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

, I는 서브 루틴의 데이터를 참조하는 방법을 알아낼 수 I는 모든 가능한 조합을 시도한 "[] {}"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

당신은 여러 다른 튜토리얼을 배우는 것처럼 보입니다. 그 중 하나는 Gabor의 PerlMaven입니다. 훌륭합니다. 하지만 지금은 스타일이 전략을 포기하고 코드에 많은 문제가 있습니다. 원하는 경우 [codereview]의 Perl 태그에 자유롭게 게시 할 수 있습니다.se]와 누군가가 한 번 살펴보고 코드 스타일의 조언을 제공하고 전략에 대해서도 알려줄 것입니다. 또한 오류 메시지를 읽어야합니다. 정확한 것은 프로그래밍의 큰 부분이며 일반적으로 오류가있는 경우 메시지가 유용합니다. :) – simbabque

+3

나는 ** simbabque **가 말한 것을지지합니다. 저는 여러분이 * Working * 코드를 [Code Review] (https://codereview.stackexchange.com/)에 게시하고 우리가 그것을 비평하도록함으로써 많은 것을 배울 것이라고 생각합니다. 저는 종종 OP 자신의 답을 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의 백 슬래시입니다. 배열에 대한 참조를 만듭니다. 두 번째 참조는 그 안에있는 각각의 배열 참조입니다.

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] 내부의 것은 배열의 심판이라고 펄을 알려줍니다이 같은 첫 번째 수준, 역 참조, 목록으로 모든 것을 얻고 싶다면 :

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

I perlreftut, perlref 및 아마도 perllol을 살펴 보시기 바랍니다.

+0

나는 ['Data :: Dump']를 선호한다. (https://metacpan.org/pod/Data::Dump) . 출력물은 훨씬 더 읽기 쉽고'dd'를 내보내므로'print Dumper \ @ commands'는'dd \ @ commands'가됩니다. 유일한 단점은 코어가 아닌 것입니다. – Borodin

+0

내 편집이 괜찮 으면 좋겠습니까? 나는 오타를 수정하고's/needed/required /'로 갔다. 단지 * required *가 절대적인 반면 * need *는 단순히 생명/사망의 문제 일 수 있기 때문이다. – Borodin

+0

@ 보 로딘 그래, 괜찮아. 고마워. 나는 당신이 알고 데이터 : 프린터를 선호합니다. ;) 그러나 나왔다 - 상자 솔루션은 여기 괜찮다고 생각했습니다. – simbabque

관련 문제