Как я могу извлечь блоки из этого файла конфигурации, используя Perl? - PullRequest
0 голосов
/ 03 ноября 2011

Я пытаюсь выполнить поиск в конфигурации Load Balancer и извлечь некоторые данные.Файл конфигурации выглядит следующим образом

pool {
name           "POOL_name1"
ttl            30
monitor all "tcp"
preferred      rr
partition "Common"

member         12.24.5.100:80
}

pool {
name           "Pool-name2"
ttl            30
monitor all "https_ignore_dwn"
preferred      rr
fallback       rr
partition "Common"

member         69.241.25.121:8443
member         69.241.25.122:8443
}   

Я пытаюсь назначить каждую конфигурацию пула для своего собственного массива, чтобы я мог перебирать массив, чтобы найти конкретные IP-адреса и имена пулов.Я попробовал следующее регулярное выражение, но это не работает.

my @POOLDATA = <FILE>;
close FILE;
foreach (@POOLDATA) {
  if (/^pool\s\{\s/ .. /^\}\s/) { 
push (@POOLCONFIG, "$_");
}
}

У кого-нибудь есть предложения о том, как разделить каждую конфигурацию пула в отдельный массив?(или лучшее предложение) Заранее благодарю за помощь

Ответы [ 3 ]

2 голосов
/ 03 ноября 2011
#!/usr/bin/env perl

use warnings; use strict;

my @pools;

my $keys = join('|', sort
    'name',
    'ttl',
    'monitor all',
    'preferred',
    'partition',
    'member'
);

my $pat = qr/^($keys)\s+([^\n]+)\n\z/;

while ( my $line = <DATA> ) {
    if ($line =~ /^pool\s+{/ ) {
        push @pools, {},
    }
    elsif (my ($key, $value) = ($line =~ $pat)) {
        $value =~ s/^"([^"]+)"\z/$1/;
        push @{ $pools[-1]->{$key} }, $value;
    }
}

use Data::Dumper;
print Dumper \@pools;


__DATA__
pool {
name           "POOL_name1"
ttl            30
monitor all "tcp"
preferred      rr
partition "Common"

member         12.24.5.100:80
}

pool {
name           "Pool-name2"
ttl            30
monitor all "https_ignore_dwn"
preferred      rr
fallback       rr
partition "Common"

member         69.241.25.121:8443
member         69.241.25.122:8443
}

Выход:

$VAR1 = [
          {
            'monitor all' => [
                               'tcp'
                             ],
            'member' => [
                          '12.24.5.100:80'
                        ],
            'ttl' => [
                       '30'
                     ],
            'name' => [
                        'POOL_name1'
                      ],
            'preferred' => [
                             'rr'
                           ],
            'partition' => [
                             'Common'
                           ]
          },
          {
            'monitor all' => [
                               'https_ignore_dwn'
                             ],
            'member' => [
                          '69.241.25.121:8443',
                          '69.241.25.122:8443'
                        ],
            'ttl' => [
                       '30'
                     ],
            'name' => [
                        'Pool-name2'
                      ],
            'preferred' => [
                             'rr'
                           ],
            'partition' => [
                             'Common'
                           ]
          }
        ];

Edit:

Конечно, вы можете проверить элемент-элемент и заполнить элемент по умолчанию, если он не найден. Фактически, имея базовую структуру, вы могли бы сделать это самостоятельно.

Один из способов сделать это - проверить конец записи пула:

while ( my $line = <DATA> ) {
    if ($line =~ /^pool\s+{/ ) {
        push @pools, {},
    }
    elsif (my ($key, $value) = ($line =~ $pat)) {
        $value =~ s/^"([^"]+)"\z/$1/;
        push @{ $pools[-1]->{$key} }, $value;
    }
    elsif ($line =~ /^\s*}/) {
        my $last = $pools[-1];

        if ($last and not $last->{member}) {
            $last->{member} = [ qw(0.0.0.0) ];
        }
    }

}
1 голос
/ 03 ноября 2011

Просто еще один способ взглянуть на это.Этот обрабатывает несколько полей, особенно.

use strict;
use warnings;
use Data::Dumper;
use English         qw<$RS>;
use List::MoreUtils qw<natatime>;
use Params::Util    qw<_ARRAY _CODE>;

# Here, we rig the record separator to break on \n}\n
local $RS = "\n}\n";

# Here, we standardize a behavior with hash duplicate keys
my $TURN_DUPS_INTO_ARRAYS = sub { 
    my ( $hr, $k, $ov, $nv ) = @_;
    if ( _ARRAY( $ov )) { 
      push @{ $ov }, $nv;
    }
    else { 
      $h->{ $k } = [ $ov, $nv ];
    }
};

# Here is a generic hashing routine
# Most of the work is figuring out how the user wants to store values
# and deal with duplicates
sub hash { 
    my ( $code, $param_name, $store_op, $on_duplicate );
    while ( my ( $peek ) = @_ ) {
        if ( $code = _CODE( $peek )) {
            last unless $param_name;

            if ( $param_name eq 'on_dup' ) { 
                $on_duplicate = shift;
            }
            elsif ( $param_name eq 'store' ) { 
                $store_op = shift;
            }
            else { 
                last;
            }
            undef $code;
        }
        else {
            my @c = $peek =~ /^-?(on_dup|store$)/;
            last unless $param_name = $c[0];
            shift;
        }
    }

    $store_op     ||= sub { $_[0]->{ $_[1] } = $_[3]; };
    $on_duplicate ||= $code || $store_op;

    my %h;
    while ( @_ ) { 
        my $k = shift;
        next unless defined( my $v = shift );
        (( exists $h{ $k } and $on_duplicate ) ? $on_duplicate 
        : $store_op 
        )->( \%h, $k, $h{ $k }, $v )
        ;
    }
    return wantarray ? %h : \%h;
}


my %pools;
# So the loop is rather small
while ( <DATA> ) { 
    # remove pool { ... } brackets
    s/\A\s*pool\s+\{\s*\n//smx;
    s/\n\s*\}\n*//smx;
    my $h 
        = hash( -on_duplicate => $TURN_DUPS_INTO_ARRAYS
       ,  map {  s/"$//; s/\s+$//; $_ } 
          map   { split /\s+"|\s{2,}/msx, $_, 2 } 
          split /\n/m
        );
    $pools{ $h->{name} } = $h;
}
print Dumper( \%pools );
### %pools

__DATA__
pool {
name           "POOL_name1"
ttl            30
monitor all "tcp"
preferred      rr
partition "Common"

member         12.24.5.100:80
}

pool {
name           "Pool-name2"
ttl            30
monitor all "https_ignore_dwn"
preferred      rr
fallback       rr
partition "Common"

member         69.241.25.121:8443
member         69.241.25.122:8443
}   

Просто заметка о функции hash, я недавно заметил большое количество сообщений о хэшах, которые обрабатывают дубликаты.Это общее решение.

1 голос
/ 03 ноября 2011

Как рекомендуется Sinan Unur , вы можете сохранить ссылку на хеш в своем массиве.Таким образом, каждый элемент вашего массива является хешем.

Кстати, структура данных Sinan немного сложнее: у вас есть массив пулов.Каждый пул - это хеш с ключом, который является значением имени элемента пула, и ссылка на массив.Таким образом, каждый элемент в пуле может иметь несколько значений (как и ваши IP-адреса).

Мой единственный комментарий - я могу использовать хэш для хранения пулов и указать его по IP-адресу.То есть, предполагая, что IP-адрес уникален для определенного пула.Таким образом, вы можете легко получить пул по IP-адресу без необходимости поиска.Я бы также сохранил параллельную структуру по имени пула по той же причине.(И поскольку каждый пул является справочным, хранение пула как по IP-адресу, так и по имени не заняло бы столько дополнительной памяти. А при обновлении одного из них будет автоматически обновляться другой).

Если выне знакомый со ссылками на Perl, а также с тем, как создать массив или хэши, или хэш массивов, вы можете взглянуть на следующие учебные пособия по Perl:

Когда вы освоите использование многослойных структур Perl, вы можете быстро научиться использоватьобъектно-ориентированное проектирование в ваших Perl-скриптах и ​​упрощение поддержки этих структур.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...