Заполнение массива хэшей массивами хэшей - PullRequest
1 голос
/ 06 октября 2009

В настоящее время я занимаюсь разработкой программного обеспечения для мониторинга, которое берет входной файл с именами серверов и 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});
 }
}

Ответы [ 3 ]

3 голосов
/ 06 октября 2009

У меня нет терпения пробираться по всему вашему коду, но держу пари, что ваша проблема связана с этим аспектом вывода Data::Dumper:

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

Другими словами, ваша структура данных содержит ссылку на другие части структуры.

Возможно, вы думаете, что делаете копию части структуры данных, но вместо этого вы получаете мелкую копию, а не глубокую копию? Например, я с подозрением отношусь к этому коду:

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

Если действительно проблема связана с мелким копированием, модуль Clone может помочь.

2 голосов
/ 06 октября 2009

Использовать лексические дескрипторы файлов, объявлять переменные в наименьшей возможной области видимости . Я не знаю, в чем ваша проблема, но, скорее всего, она вызвана тем, что какая-то переменная сохраняется дольше, чем вы думаете.

1 голос
/ 07 октября 2009

Я предполагаю, что это потому, что эти две строки в итоге выдвигают одну и ту же ссылку на хеш в двух местах - поэтому, если вы измените содержимое хеш-ссылки в одном месте, изменится и другое, что, вероятно, не то, что вы хотите для значений по умолчанию.

Как указал FM, именно поэтому у вас на выходе Dumper есть циклическая ссылка.

Если кто-то, кого я жду, чтобы выйти из телефона, займет достаточно много времени, я проведу рефакторинг вашегокод для вас.

Обновление: хорошо, поэтому, не зная полного сценария, трудно сказать, является ли это разумным подходом.конечно, вы должны взглянуть на различные модули синтаксического анализа INI в CPAN, но вот очень быстрая настройка вашего кода, оставляя существующую логическую структуру на месте:

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
                                 }
                               ]
                }
      }
    ];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...