1

Perl CLI フレームワークを使用してスクリプトを記述しています。ここで、制御モジュールからサブコマンド モジュールに変数を渡したいと思います。制御モジュールで変数をグローバル変数として設定しようとしましたが、サブコマンド モジュールはまだ変数を取得できません。同じモジュール内でグローバル変数を共有することさえできません。スクリプトを実行すると、いくつかのエラー メッセージが表示されます。

[root@old]# perl pc --ip=dsfa --device dsfasdf on Power/Control.pm 行 63 の連結 (.) または文字列で初期化されていない値 $Power::Control::data が使用されています。

globla データは、連結 (.) または Power/Control.pm 75 行目の文字列で初期化されていない値 $Power::Control::data を使用しています。

親からのデータは

デバイス名は 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;
4

1 に答える 1

0

これについてフォローアップしていただきありがとうございます。lib/Power/Control.pmファイルを整理して典型的なレイアウトに分割するのに1、2分かかり、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;

前述のように、モジュール ディレクトリ タイプのレイアウトでファイルを分離したので、2 つ目のファイルがあります。私は自分の便宜のためにこれを行ったので、同じことをしなければならないとは思わないでください.

# 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;         

あなたの最初のアプローチがうまくいかなかった理由は、エラーメッセージが示したように、初期化されていない変数だったと思います。私の試みた説明は次のとおりです。

  1. use lib 'lib'; そうしないと、スクリプトに use Power::Control;完全な @INC がなく、見つけることができませんでしたPower::Control。これを修正すると、あなたと同じエラーが発生しました。これは、CLI::Framework を別の方法で設定したか、独自のモジュールを @INC のどこかに配置した可能性があることを示唆しています。

  2. "our $data ; 行 53を変更するlib/Power/Control.pm our $data = "in the global scope"; と (それ以外の場合は未定義)、スクリプトを実行したときにそのメッセージが表示されます。"$data" 値が init() サブルーチン内から設定されていない init print "\n The ip address is $data\n";() サブルーチンの 60 行目あたりを に置き換えると、期待どおりの出力が得lib/Power/Control.pmられprint "\n The ip address is $opts->{ip}\n";ます。$data = 内部init()を変更して行を読み取りmy $otherdata = ...、それに応じて調整すると、 variable のさまざまな字句値の効果についても理解できますprint

  3. まだ終えていません!説明を確認/編集し、変数のスコープと、$data変数がこのCLI::Frameworkアプリ内で何をしているのかについての参照をいくつか追加します。

-dところで、それはトリッキーですが、コマンドにスイッチを追加するだけで perl デバッガーでスクリプトを実行することで、多くのことを理解できます。

perl -d pc --ip=dsfa --device dsfasdf on.

次に、実行中にスクリプトをステップスルーし、変数値のダンプ、トレースなどを試みます。

onコマンド引数をオプションの前に置こうとすると、--ip=別の種類の問題が発生します。コマンド ライン引数の解析が少し脆弱です。それを修正したり、少なくともFailed parsing of command optionsもう少し意味のあるものにするために追加できる洗練されたチェックがある可能性があります(たとえば、使用画面をユーザーに送信します)。

あなたのプロジェクトで頑張ってください。

于 2013-06-16T00:01:50.563 に答える