3

要求是从命令行参数传递模块名称和函数名称。我需要在程序中获取命令行参数,并且需要从该模块调用该函数

例如,调用带有 2 个参数的 try.pl 程序: MODULE1(Module name) Display(Function name)

 perl try.pl MODULE1 Display 

我想要这样的东西,但它不起作用,请指导我:

use $ARGV[0];
& $ARGV[0]::$ARGV[1]();
4

8 回答 8

9

假设函数不是类方法,试试这个:

#!/usr/bin/perl
use strict;
use warnings;

my ( $package, $function ) = @ARGV;

eval "use $package (); ${package}::$function()";
die $@ if $@;

请记住,这种技术对代码注入非常开放。(参数可以很容易地包含任何 Perl 代码而不是模块名称。)

于 2008-10-16T16:33:11.953 回答
7

There's many ways to do this. One of them is:

#!/usr/bin/perl
use strict;
use warnings;

my ( $package, $function ) = @ARGV;

eval "use $package; 1" or die $@;

$package->$function();  

Note the the first argument of the function will be $package.

于 2008-10-16T16:17:35.170 回答
4

假设模块导出函数,应该这样做:

perl -Mmodule -e function
于 2008-10-16T16:25:10.833 回答
3

如果你想确保你的 perl 脚本是安全的(或者至少,防止自己不小心做一些愚蠢的事情),我会避免在没有至少某种检查的情况下对传入脚本的数据进行任何类型的评估。但是,如果您无论如何都要进行某种检查,并且最终明确地检查了输入,那么您最好明确地拼出您想要调用的女巫方法。您可以使用“已知良好”方法设置散列,从而记录您想要调用的所有内容并同时保护自己。

my %routines = (
    Module => {
        Routine1 => \&Module::Method,
        Routine2 => \&Module::Method2, 
    },
    Module2 => { 
        # and so on
    },
);

my $module  = shift @ARGV;
my $routine = shift @ARGV;

if (defined $module
    && defined $routine
    && exists $routines{$module}            # use `exists` to prevent 
    && exists $routines{$module}{$routine}) # unnecessary autovivication
{
    $routines{$module}{$routine}->(@ARGV); # with remaining command line args
}
else { } # error handling

作为此方法的一个简洁的副作用,您可以简单地遍历可用于任何类型帮助输出的方法:

print "Available commands:\n";
foreach my $module (keys %routines)
{
    foreach my $routine (keys %$module)
    {
        print "$module::$routine\n";
    }
}  
于 2008-10-16T19:50:04.320 回答
2

按照 Leon 的说法,如果 perl 模块没有导出它,你可以这样称呼它

perl -MMyModule -e 'MyModule::doit()'

前提是子在该包中。

如果它一直导出子(in @EXPORT),那么 Leon's 将起作用:

perl -MMyModule -e doit

如果它是可选的导出(in @EXPORT_OK),那么您可以这样做。

perl -MMyModule=doit -e doit

但是第一个在 sub 被定义到包的任何情况下都可以工作,我可能会在最后一个上使用那个。

于 2008-10-16T17:07:30.310 回答
2

总是像这样启动你的 Perl:

use strict;
use warnings 'all';

然后这样做:

no strict 'refs';
my ($class, $method) = @_;
(my $file = "$class.pm") =~ s/::/\//g;
require $file;
&{"$class\::$method"}();

无论你做什么,都尽量不要评估“$string”。

于 2008-10-17T01:26:50.270 回答
2

好吧,对于您修改后的问题,您可以这样做:

use strict;
use warnings;

{
    no strict;
    use Symbol qw<qualify>;
    my $symb = qualify( $ARGV[1], $ARGV[0] );
    unless ( defined &{$symb} ) { 
        die "&$ARGV[1] not defined to package $ARGV[0]\::";
    }
    &{$symb};
}

而且因为您是在命令行中指定它,所以从命令行包含的最简单方法是-M标志。

perl -MMyModule try.pl MyModule a_subroutine_which_does_something_cool

但你总是可以

eval "use $ARGV[0];"; 

但这很容易被注入:

perl try.pl "Carp; `do something disastrous`;" no_op
于 2008-10-17T02:45:59.160 回答
1

我会使用UNIVERSAL::require。它允许您从变量中获取或使用模块。所以你的代码会变成这样:

use UNIVERSAL::require;

$ARGV[0]->use or die $UNIVERSAL::require::ERROR;
$ARGV[0]::$ARGV[1]();

免责声明:我没有测试该代码,并且我同意 Robert P 关于可能有比将这些作为命令行参数传递更好的解决方案的评论。

于 2008-10-21T01:20:56.257 回答