我正在使用Perl CLI Framework编写一些脚本。现在我想将变量从控制模块传递给子命令模块。我试图将变量设置为控制模块中的全局变量,但是子命令模块仍然无法获取变量。它甚至无法在同一模块中共享全局变量。执行脚本时会出现一些错误消息:
[root @ old] #perl pc --ip = dsfa --device dsfasdf on 在Power / Control.pm第63行使用未初始化的值$ Power :: Control ::数据连接(。)或字符串。
全局数据是 在Power / Control.pm第75行使用未初始化的值$ Power :: Control ::数据连接(。)或字符串。
来自父母的数据是
设备名称为dsfasdf
ip地址是dsfa
这是
上的命令这是脚本pc:
#! /usr/bin/perl
use strict;
use warnings;
use Power::Control;
use lib 'lib';
# ---- EXECUTION ----
Power::Control->run(); # Launch command
这是Power / Control.pm:
package Power::Control;
use base qw( CLI::Framework );
use strict;
use warnings;
sub usage_text {
qq{
$0 [--verbose|v]:
OPTIONS:
--verbose -v: be vebose
ARGUMENTS (subcommands):
on: power on the device
off: power off the device
reboot: reboot the device
version: show PDU version
status: show PDU status
sysstat: show PDU sysstatus
}
}
sub option_spec {
[ 'device|d=s' => 'device name' ],
[ 'ip=s' => 'ip address' ],
[ 'user|u=s' => 'user name' ],
[ 'password|p=s' => 'password' ],
[ 'interval|i=s' => 'interval' ],
[ 'brand|b=s' => 'brand' ],
[ 'community|c=s' => 'community' ],
[ 'version|v=s' => 'version' ],
}
sub command_map {
on => 'Power::Control::Command::On',
off => 'Power::Control::Command::Off',
reboot => 'Power::Control::Command::Reboot',
version => 'Power::Control::Command::Version',
status => 'Power::Control::Command::Status',
sysstat => 'Power::Control::Command::Sysstat',
}
sub command_alias {
r => 'reboot',
v => 'version',
st => 'status',
sys => 'sysstat',
}
our $opts;
our $self;
our $data;
sub init {
($self, $opts) = @_;
$data = $opts->{'ip'};
print "\n The device name is $opts->{'device'}\n";
print "\n The ip address is $data\n";
}
print "\n The globla data is $data\n";
1;
# ---- COMMAND: On ----
package Power::Control::Command::On;
use base qw( CLI::Framework::Command );
use strict;
use warnings;
use Power::Control;
use Data::Dumper;
print "\n The data from parent is $data \n";
sub usage_text {
q{
on [--d=<device name>: Power on the device
}
}
#sub option_spec {
# [ 'device|d=s@' => 'device name' ],
#}
sub run {
print "\n This is the command on\n";
}
1;
答案 0 :(得分:0)
感谢您对此采取后续行动。我花了一两分钟来组织和分离文件到一个典型的lib/Power/Control.pm
和lib/Power/Control/Command/On.pm
布局,并清理了一些东西,这是我得到的输出:
[localhost ~/tmp%] perl stackex-pc --ip=127.0.0.1 --device=pants on
The device name is pants
The ip address is 127.0.0.1
This is the command "on"
我认为或多或少是你想要的。我将在下面添加我对我的想法的解释,但首先我会包含我的文件,你可以在家里试试。如果它有效,那么你可以接受我的答案。如果我给出一个不错的解释,那么其他人可以投票给我!首先,这是脚本:
#! /usr/local/bin/perl
#
# stackex-pc
# Question: http://stackoverflow.com/questions/17054798
use strict;
use warnings;
use lib 'lib' ;
use Power::Control;
# ---- EXECUTION ----
Power::Control->run(); # Launch command
这是包裹:
# lib/Power/Control.pm
# Question: http://stackoverflow.com/questions/17054798
package Power::Control;
use base qw( CLI::Framework );
use strict;
use warnings;
our ($data, $opts, $self);
sub usage_text {
qq{
$0 [--verbose|v]:
OPTIONS:
--verbose -v: be vebose
ARGUMENTS (subcommands):
on: power on the device
off: power off the device
reboot: reboot the device
version: show PDU version
status: show PDU status
sysstat: show PDU sysstatus
}
}
sub option_spec {
[ 'device|d=s' => 'device name' ],
[ 'ip=s' => 'ip address' ],
[ 'user|u=s' => 'user name' ],
[ 'password|p=s' => 'password' ],
[ 'interval|i=s' => 'interval' ],
[ 'brand|b=s' => 'brand' ],
[ 'community|c=s' => 'community' ],
[ 'version|v=s' => 'version' ],
}
sub command_map {
on => 'Power::Control::Command::On',
off => 'Power::Control::Command::Off',
reboot => 'Power::Control::Command::Reboot',
version => 'Power::Control::Command::Version',
status => 'Power::Control::Command::Status',
sysstat => 'Power::Control::Command::Sysstat',
}
sub command_alias {
r => 'reboot',
v => 'version',
st => 'status',
sys => 'sysstat',
}
sub init {
($self, $opts) = @_;
print "\n The device name is $opts->{device}\n";
print "\n The ip address is $opts->{ip}\n";
}
1;
如上所述,我将模块目录类型布局中的文件分开,因此有第二个文件。我这样做是为了方便,所以不要觉得你必须做同样的事情。
# lib/Power/Control/Command/On.pm
# Question: http://stackoverflow.com/questions/17054798
package Power::Control::Command::On;
use base qw( CLI::Framework::Command );
use strict;
use warnings;
use Power::Control;
sub usage_text {
q{
on [--d=<device name>: Power on the device
}
}
sub run {
print "\n This is the command \"on\" \n";
exit ;
}
1;
我认为你的第一种方法不起作用的原因是 - 正如错误信息所示 - 未初始化的变量。我的尝试解释如下:
我需要在{/ em> use lib 'lib';
之前放置use Power::Control;
,否则脚本将没有完整的@INC而无法找到Power::Control
。当我解决这个问题时,我得到了和你一样的错误。这表明您可能以不同的方式设置CLI :: Framework,或者将自己的模块放在@INC中的某个位置。
如果您更改"our $data ;
lib/Power/Control.pm
的第53行上的our $data = "in the global scope";
- 否则未定义 - 您将在运行脚本时看到该消息。 “$ data”值未从init()子例程内部设置如果在print "\n The ip address is $data\n";
中使用lib/Power/Control.pm
的第60行的init()子例程中替换print "\n The ip address is $opts->{ip}\n";
,您将获得更像您期望的输出。如果您将$data =
内的init()
更改为my $otherdata = ...
并相应地调整print
行,您还可以了解变量的不同词汇值的效果。
我还没完成!我将审核/编辑我的解释,并添加一些有关变量范围的引用,以及$data
变量在此CLI::Framework
应用内所做的内容。
-d
开关:
perl -d pc --ip=dsfa --device dsfasdf on
。
然后在脚本运行时单步执行,尝试转储变量值,跟踪等。
如果您尝试在on
选项之前放置--ip=
命令参数,您会看到另一种问题:命令行参数解析有点脆弱。您可以添加一个优雅的检查来修复它,或者至少使Failed parsing of command options
更有意义(例如,将使用情况屏幕发送给用户)。
祝你的项目好运。