如何插入变量以从模块调用Perl函数?

时间:2008-10-16 15:37:04

标签: perl variables interpolation

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

例如,调用带有2个参数的try.pl程序:MODULE1(模块名称)显示(函数名称)

 perl try.pl MODULE1 Display 

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

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

8 个答案:

答案 0 :(得分:9)

假设该函数不是类方法,请尝试:

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

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

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

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

答案 1 :(得分:7)

有很多方法可以做到这一点。其中之一是:

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

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

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

$package->$function();  

注意函数的第一个参数是$ package。

答案 2 :(得分:4)

假设模块导出该函数,则应执行以下操作:

perl -Mmodule -e function

答案 3 :(得分: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";
    }
}  

答案 4 :(得分:2)

根据Leon的说法,如果perl模块没有导出它,你可以像这样调用它

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

如果sub在该包中。

如果它一直导出子(在@EXPORT中),那么Leon会工作:

perl -MMyModule -e doit

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

perl -MMyModule=doit -e doit

但是第一个将适用于sub被定义为包的任何情况,并且我可能在最后一个上使用那个。

答案 5 :(得分:2)

始终像这样启动你的Perl:

use strict;
use warnings 'all';

然后这样做:

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

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

答案 6 :(得分: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

答案 7 :(得分:1)

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

use UNIVERSAL::require;

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

免责声明:我没有测试该代码,我同意Robert P的评论,可能有更好的解决方案,而不是将它们作为命令行参数传递。