要求是从命令行参数传递模块名称和函数名称。 我需要在程序中获取命令行参数,我需要从该模块中调用该函数
例如,调用带有2个参数的try.pl程序:MODULE1(模块名称)显示(函数名称)
perl try.pl MODULE1 Display
我想要这样的事情,但它不起作用,请指导我:
use $ARGV[0];
& $ARGV[0]::$ARGV[1]();
答案 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的评论,可能有更好的解决方案,而不是将它们作为命令行参数传递。