提问人:Sanjay 提问时间:10/16/2008 最后编辑:MatSanjay 更新时间:9/16/2012 访问量:8325
如何插值变量以从模块调用 Perl 函数?
How do I interpolate variables to call a Perl function from a module?
问:
要求是从命令行参数传递模块名称和函数名称。 我需要在程序中获取命令行参数,并且需要从该模块调用该函数
例如,使用 2 个参数调用 try.pl 程序: MODULE1(模块名称) Display(函数名称)
perl try.pl MODULE1 Display
我想要这样的事情,但它不起作用,请指导我:
use $ARGV[0];
& $ARGV[0]::$ARGV[1]();
答:
有很多方法可以做到这一点。其中之一是:
#!/usr/bin/perl
use strict;
use warnings;
my ( $package, $function ) = @ARGV;
eval "use $package; 1" or die $@;
$package->$function();
请注意,该函数的第一个参数将是$package。
假设模块导出函数,这应该做:
perl -Mmodule -e function
评论
假设该函数不是类方法,请尝试以下操作:
#!/usr/bin/perl
use strict;
use warnings;
my ( $package, $function ) = @ARGV;
eval "use $package (); ${package}::$function()";
die $@ if $@;
请记住,这种技术对代码注入是开放的。(参数可以很容易地包含任何 Perl 代码,而不是模块名称。
评论
根据 Leon 的说法,如果 perl 模块没有导出它,你可以这样调用它
perl -MMyModule -e 'MyModule::doit()'
前提是潜艇在该包中。
如果它一直导出 sub (in ),那么 Leon 将起作用:@EXPORT
perl -MMyModule -e doit
如果它是可选的导出 (in ),那么您可以这样做。@EXPORT_OK
perl -MMyModule=doit -e doit
但是第一个在将 sub 定义为包的任何情况下都有效,我可能会使用那个而不是最后一个。
如果你想确保你的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";
}
}
总是像这样启动你的Perl:
use strict;
use warnings 'all';
然后这样做:
no strict 'refs';
my ($class, $method) = @_;
(my $file = "$class.pm") =~ s/::/\//g;
require $file;
&{"$class\::$method"}();
无论你做什么,都尽量不要评价“$string”。
好吧,对于您修改后的问题,您可以这样做:
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
评论
fermat c:
我会使用 UNIVERSAL::require。它允许您要求或使用变量中的模块。因此,您的代码将更改为如下所示:
use UNIVERSAL::require;
$ARGV[0]->use or die $UNIVERSAL::require::ERROR;
$ARGV[0]::$ARGV[1]();
免责声明:我没有测试该代码,我同意 Robert P 的评论,即可能有比将这些作为命令行参数传递更好的解决方案。
评论