[英]How can I extract blocks from this configuration file using Perl?
我正在嘗試搜索負載均衡器配置並提取一些數據。 配置文件如下所示
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, "$_");
}
}
有人對如何將每個池配置分成自己的陣列有建議嗎? (或更好的建議)預先感謝您的幫助
#!/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' ] } ];
當然,您可以檢查成員元素,如果找不到則填寫默認元素。 實際上,有了基本的結構,您應該可以自己做到這一點。
一種方法是檢查池記錄的結尾:
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) ];
}
}
}
按照Sinan Unur的建議,您可以在數組中存儲對哈希的引用。 這樣,數組的每個元素都是一個哈希。
順便說一下,思南的數據結構要復雜一些:您有一組池。 每個池都是一個哈希,其哈希值包含池元素名稱的值和對數組的引用 。 這樣,池中的每個元素都可以具有多個值(就像您的IP地址一樣)。
我唯一的評論是,我可能會使用散列來存儲池,並按IP地址對其進行鍵控。 也就是說,假設IP地址對於特定池是唯一的。 這樣,您無需搜索即可輕松通過IP地址創建一個池。 出於相同的原因,我還將按池名稱保留並行結構。 (而且,由於每個池都是引用,因此通過IP地址和名稱存儲該池不會占用過多的內存。並且,更新一個池會自動更新另一個池)。
如果您不熟悉Perl引用,或者不熟悉如何創建數組或哈希或數組散列,則可以閱讀以下Perl教程:
一旦掌握了使用多層Perl結構的知識,便可以快速學習如何在Perl腳本中使用面向對象的設計,並使維護這些結構非常容易。
只是另一種看待方式。 這個專門處理多個成員字段。
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
函數的注釋,我注意到最近有大量關於處理重復項的哈希的文章。 這是一個通用的解決方案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.