1

私は現在、サーバー名とIPアドレスの入力ファイルを受け取り、情報の基本的なデータベースを作成する監視ソフトウェアを開発しています。設定ファイルを処理するときにいくつかの値をデフォルトにしたいのですが、ループの周りで初めて正常に動作しますが、後続のエントリは奇妙なもので作成されます(おそらく正しく、コードは間違っています。コードは私が要求したことを正確に実行していますが、必ずしも私が実行したいことを実行しているわけではありません)。

以下のコードからの出力は次のようになります。

$VAR1 = [
      {
        'IPAddress' => '196.8.150.163',
        'Boxname' => 'MPLRDFDSOAK1',
        'CurrentStatusInfo' => {
                                 'LineHandlersRunning' => [
                                                            {
                                                              'NumberOfGaps' => 0,
                                                        'LineHandlerName' => 'DEFAULT',
                                                        'NumberOfCommLinkDowns' => 0,
                                                              'LineHandlerUpTime' => 0,
                                                              'MemoryUsage' => 0
                                                            }
                                                          ]
                               },
        'PreviousStatusInfo' => {
                                  'LineHandlersRunning' => 
                        $VAR1->[0]{'CurrentStatusInfo'}{'LineHandlersRunning'}[0]
                                                         ]
                                }
      },
      {
        'IPAddress' => '196.8.150.164',
        'Boxname' => 'MPLRDFDSOAK2',
        'CurrentStatusInfo' => {
                                 'LineHandlersRunning' => 
                        $VAR1->[0]{'CurrentStatusInfo'}{'LineHandlersRunning'}
                               },
        'PreviousStatusInfo' => {
                                  'LineHandlersRunning' => 
                        $VAR1->[0]{'PreviousStatusInfo'}{'LineHandlersRunning'}
                                }
      }
    ];

コードは次のとおりです。

#######################################################################################
# Version History                                                                     #
#######################################################################################
# example of the ini file
#box=>MPLRDFDSOAK1;ip=>196.8.150.163
#box=>MPLRDFDSOAK2;ip=>196.8.150.164

use strict;
use warnings;

# include the library to allow easy access to command line arguments
use Getopt::Long;

# include the data dumper utility
use Data::Dumper;

my $usageInstructions = "Some instructions\n";
my $showMeTheInstructions = "";
my $iniFileToReadIn = "";
my @boxes;

# read in the command line arguments
GetOptions( "ini=s"  => \$iniFileToReadIn,
  "H|h|?!" => \$showMeTheInstructions);

if ($showMeTheInstructions)
{
 print $usageInstructions;
 exit 0;
}

readInINIFileIn($iniFileToReadIn, \@boxes) if ($iniFileToReadIn ne "");

print Dumper(\@boxes);
print "\n\#\n\# END OF DATA DUMP\n\#\n\n";
exit 0;

#######################################################################################
# subroutine to read in the ini file and create the empty records for the boxes 
# specified
sub readInINIFileIn
{ 
 my ($iniFile, $pointerToBoxes) = @_;

 my $noCRLFOnString = "";

 # open the file
 open (ConfigFile, "<$iniFile") || die $!;

 # read in all the lines into an array
 my @configurationItems = <ConfigFile>;

 # close the file
 close (ConfigFile);

 # temporary record storage
 my %tempRecord;

 # create the defaults for all boxes
 my @LineHandlersRunning;

 my %tmpLineHandlerRunning = ( LineHandlerName => "DEFAULT", 
     LineHandlerUpTime => 0, 
     NumberOfCommLinkDowns => 0, 
     NumberOfGaps => 0, 
     MemoryUsage => 0 );

 push (@LineHandlersRunning, {%tmpLineHandlerRunning});

 my %CurrentStatusInfo;
 my %PreviousStatusInfo;

 push @{ $CurrentStatusInfo{'LineHandlersRunning'} },          @LineHandlersRunning;
 push @{ $PreviousStatusInfo{'LineHandlersRunning'} },         @LineHandlersRunning;

 # loop through the config file and create the defaults for the database of boxes
 foreach my $configLine (@configurationItems)
 {
  my @TokenisedLineFromFileItems = ();
  my @TokenisedLineFromFileNameValuePairs = ();

  # store parameters
  # each line will be ; separated then => separated, as in each one will have a number of items separated by ;'s and
  # each item will be be a name & value pair separated by =>'s
  @TokenisedLineFromFileItems = split(/;/,$configLine);

  # remove quote marks around the outside of each element of the newly created array
  s/^"|"$//g foreach @TokenisedLineFromFileItems;

  # create information in database record to add to boxes
  foreach my $NameValuePair (@TokenisedLineFromFileItems)
  {
   @TokenisedLineFromFileNameValuePairs = split(/=>/,$NameValuePair);
   $noCRLFOnString = $TokenisedLineFromFileNameValuePairs[1];
   $noCRLFOnString  =~ s/(\n|\r)//g;

   $tempRecord{'Boxname'} = $noCRLFOnString if ($TokenisedLineFromFileNameValuePairs[0] eq "box");
   $tempRecord{'IPAddress'} = $noCRLFOnString if ($TokenisedLineFromFileNameValuePairs[0] eq "ip");
  }

  # add all other defaults as blank
  $tempRecord{'CurrentStatusInfo'} = {%CurrentStatusInfo};
  $tempRecord{'PreviousStatusInfo'} = {%PreviousStatusInfo};

  push(@$pointerToBoxes, {%tempRecord});
 }
}
4

3 に答える 3

3

私はあなたのすべてのコードを通り抜ける忍耐力を持っていませんが、あなたの問題はData::Dumper出力のこの側面に関連しているに違いありません:

$VAR1->[0]{'CurrentStatusInfo'}{'LineHandlersRunning'}[0]

つまり、データ構造には、構造の他の部分への参照が含まれています。

おそらく、データ構造の一部のコピーを作成していると思いますが、代わりに、深いコピーではなく浅いコピーを取得していますか?たとえば、私はこのコードに疑いを持っています:

$tempRecord{'CurrentStatusInfo'} = {%CurrentStatusInfo};
$tempRecord{'PreviousStatusInfo'} = {%PreviousStatusInfo};

実際に問題が浅いコピーに関連している場合は、クローンモジュールが役立つ可能性があります。

于 2009-10-06T14:22:33.177 に答える
2

字句ファイルハンドルを使用し、可能な限り最小のスコープで変数を宣言します。私はあなたの問題が何であるかを知りませんが、それはおそらくあなたが思っているよりも長く持続するいくつかの変数によって引き起こされます。

于 2009-10-06T14:23:35.480 に答える
1

これらの2行が同じハッシュ参照を2つの場所にプッシュするためだと思います。したがって、一方の場所でハッシュ参照の内容を変更すると、もう一方の場所も変更されます。これは、デフォルト値に必要なものではない可能性があります。

FMが指摘したように、これがダンパー出力に循環参照がある理由です。

電話を切るのを待っている人が十分に時間がかかる場合は、コードをリファクタリングします。

更新:わかりました。完全なシナリオを知らなければ、これが賢明なアプローチであるかどうかを判断するのは困難です。確かに、CPANのさまざまなINI解析モジュールを確認する必要がありますが、既存のロジック構造をそのままにして、コードを非常にすばやく調整します。

use strict;
use warnings;

use Getopt::Long;
use Data::Dumper;

my $cmd_help = "Some instructions\n";
my $show_help = "";
my $ini_file_path = "";

# read in the command line arguments
GetOptions( "ini=s"  => \$ini_file_path,
            "H|h|?!" => \$show_help );

if ($show_help) {
    print $cmd_help;
    exit 0;
}

if (! -f $ini_file_path) {
    die "File '$ini_file_path' doesn't seem to exist.";
}

my $boxes = read_ini_file($ini_file_path);

print Dumper($boxes);

exit 0;

=head2 read_ini_file

read in the ini file and create the empty records for the boxes 

=cut

sub read_ini_file { 
    my ($ini_file) = @_;

    my @boxes;

    my @config_lines;
    {
        # consider using File::Slurp
        open (my $ini_fh, '<', $ini_file_path) || die $!;

        @config_lines = <$ini_fh>;
        chomp @config_lines; # remove \r\n

        # file handle will close when $ini_fh goes out of scope
    }

    # create the defaults for all boxes
    my %line_handlers_running_defaults = ( LineHandlerName => "DEFAULT", 
                                           LineHandlerUpTime => 0, 
                                           NumberOfCommLinkDowns => 0, 
                                           NumberOfGaps => 0, 
                                           MemoryUsage => 0 );

    # loop through the config file and create the defaults for the database of boxes
    foreach my $line (@config_lines) {

        my %record;

        my @token_pairs = map { s/^"//; s/^$//; $_ } split(/;/,$line);

        # create information in database record to add to boxes
        foreach my $pair (@token_pairs) {
            my ($key, $val) = split(/=>/,$pair);

            $record{Boxname} = $val if $key eq "box";
            $record{IPAddress} = $val if $key eq "ip";
        }

        # add all other defaults as blank
        $record{CurrentStatusInfo} = { LineHandlersRunning => [{%line_handlers_running_defaults}] };
        $record{PreviousStatusInfo} = { LineHandlersRunning => [{%line_handlers_running_defaults}] };

        push @boxes, \%record;
    }

    return \@boxes;
}

この出力を与えます:

$VAR1 = [
      {
    'IPAddress' => '196.8.150.163',
    'CurrentStatusInfo' => {
                 'LineHandlersRunning' => [
                                {
                                  'NumberOfGaps' => 0,
                                  'LineHandlerName' => 'DEFAULT',
                                  'NumberOfCommLinkDowns' => 0,
                                  'LineHandlerUpTime' => 0,
                                  'MemoryUsage' => 0
                                }
                              ]
                   },
    'Boxname' => 'MPLRDFDSOAK1',
    'PreviousStatusInfo' => {
                  'LineHandlersRunning' => [
                                 {
                                   'NumberOfGaps' => 0,
                                   'LineHandlerName' => 'DEFAULT',
                                   'NumberOfCommLinkDowns' => 0,
                                   'LineHandlerUpTime' => 0,
                                   'MemoryUsage' => 0
                                 }
                               ]
                }
      },
      {
    'IPAddress' => '196.8.150.164',
    'CurrentStatusInfo' => {
                 'LineHandlersRunning' => [
                                {
                                  'NumberOfGaps' => 0,
                                  'LineHandlerName' => 'DEFAULT',
                                  'NumberOfCommLinkDowns' => 0,
                                  'LineHandlerUpTime' => 0,
                                  'MemoryUsage' => 0
                                }
                              ]
                   },
    'Boxname' => 'MPLRDFDSOAK2',
    'PreviousStatusInfo' => {
                  'LineHandlersRunning' => [
                                 {
                                   'NumberOfGaps' => 0,
                                   'LineHandlerName' => 'DEFAULT',
                                   'NumberOfCommLinkDowns' => 0,
                                   'LineHandlerUpTime' => 0,
                                   'MemoryUsage' => 0
                                 }
                               ]
                }
      }
    ];
于 2009-10-07T08:34:14.600 に答える