将数组数组传递给Perl中的子例程

时间:2017-12-04 20:29:18

标签: perl

我正在尝试创建一个子程序,它将一个数组数组传递给子程序,这样命令就可以在不同的目录中并行运行。

基本上,每个第一个索引都针对每个命令目录对。第二个索引有两个变量:directory和命令本身。

例如,

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

但是,我无法弄清楚如何在子程序中引用数据,我已经尝试了“[] {}”的所有可能组合,我可以在许多不同的位置进行思考。我已经阅读了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);

此特定配置会产生错误

703404669@ssxfisctimga004:~/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.

如何读取子程序中的目录命令对?

1 个答案:

答案 0 :(得分: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];

如果你想把整个事情作为一个列表,取消引用这样的第一级,告诉Perl $foo->[0]里面的内容是数组引用:

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

我建议您查看perlreftutperlrefperllol