Perl - помощь с хеш и сбросом записей
-
30-09-2019 - |
Вопрос
У меня есть сценарий Perl, который поддерживает только последний набор записей для именованного набора, и у меня есть более одного набора записей. Итак, его над записью данных в хэш и просто сохраняя последний набор. Мне нужна помощь в печати всех записей. Спасибо!
Вот копия моего сценария:
#!/usr/local/bin/perl
use strict;
use warnings;
use Data::Dumper;
my ($ServerName)=@ARGV;
my %MyItems;
foreach my $ServerName(@ARGV){
while (my $line = <>){
chomp $line;
if ($line =~ m/.* \w+ \d{2} (\d{2}:\d{2}:\d{2}) \d{4}: ([^:]+):backup:/){
my $ServerName = basename $ARGV, '.mydomain.com.backup-software.log'; #$ARGV is reading input from command line
my $BckupSet =$2;
my $BckupVal=$1;
$MyItems{$ServerName}{$BckupSet}->{'1-Server'} = $ServerName;
$MyItems{$ServerName}{$BckupSet}->{'2-BackupSet'} = $BckupSet;
$MyItems{$ServerName}{$BckupSet}->{'3-StartTime'} = $BckupVal;
if ($line =~ m/(backup-date)[:=](.+)/){
my $BckupKey="4-DateStamp";
my $BckupVal=$2;
$MyItems{$ServerName}{$BckupSet}->{$BckupKey} = $BckupVal;
}
if ($line =~ m/(backup-time)[:=](.+)/){
my $BckupKey="5-Duration";
my $BckupVal=$2;
$MyItems{$ServerName}{$BckupSet}->{$BckupKey} = $BckupVal;
}
if ($line =~ m/(backup-size)[:=](.+)/){
my $BckupKey="6-Size";
my $BckupVal=$2;
$MyItems{$ServerName}{$BckupSet}->{$BckupKey} = $BckupVal;
}
if ($line =~ m/(Backup succeeded)/){
my $BckupKey="7-Status";
my $BckupVal="Succeeded";
$MyItems{$ServerName}{$BckupSet}->{$BckupKey} = $BckupVal;
}
if ($line =~ m/(ERROR)[:=](.+)/){
my $BckupKey="8-Status";
my $BckupVal="Unsuccessful";
$MyItems{$ServerName}{$BckupSet}->{$BckupKey} = $BckupVal;
print "$BckupKey=$BckupVal\n" if debug;
}
}
} #endwhile
print Dumper(\%MyItems);
for my $ServerName(keys%MyItems){
for my $BckupSet(keys%{$MyItems{$ServerName}}){
for(sort keys%{$MyItems{$ServerName}{$BckupSet}}){
#print$_,'=>',$MyItems{$ServerName}{$BckupSet}{$_},';';
print$_,'=',$MyItems{$ServerName}{$BckupSet}{$_},';';
}
print"\n";
}
}
} #END foreach
Вот что похоже, когда он сбрасывает:
$VAR1 = {
'server1.name.colo' => {
'set1' => {
'3-StartTime' => '07:08:15',
'1-Server' => 'server1.name.colo',
'6-Size' => '72.04 GB',
'7-Status' => 'Succeeded',
'4-DateStamp' => '20100820060002',
'5-Duration' => '01:08:13',
'2-BackupSet' => 'set1',
'8-Status' => 'Unsuccessful'
},
'set2' => {
'7-Status' => 'Succeeded',
'6-Size' => '187.24 GB',
'3-StartTime' => '01:51:25',
'4-DateStamp' => '20100820000003',
'1-Server' => 'server1.name.colo',
'5-Duration' => '01:51:21',
'2-BackupSet' => 'set2'
},
'set3' => {
'3-StartTime' => '23:00:05',
'4-DateStamp' => '20100814230003',
'1-Server' => 'server1.name.colo',
'8-Status' => 'Unsuccessful',
'2-BackupSet' => 'set3'
},
'set4' => {
'7-Status' => 'Succeeded',
'6-Size' => '427.75 GB',
'3-StartTime' => '00:43:20',
'4-DateStamp' => '20100819200004',
'1-Server' => 'server1.name.colo',
'5-Duration' => '04:43:14',
'2-BackupSet' => 'set4'
},
'set3' => {
'7-Status' => 'Succeeded',
'6-Size' => '46.42 GB',
'3-StartTime' => '04:42:59',
'4-DateStamp' => '20100820040002',
'1-Server' => 'server1.name.colo',
'5-Duration' => '00:42:56',
'2-BackupSet' => 'set3'
}
}
};
Решение
На основании вывода отладки, похоже, ваша проблема здесь:
if ($line =~ m/(ERROR)[:=](.+)/){
my $BckupKey="8-Status";
my $BckupVal="Unsuccessful";
$MyItems{$ServerName}{$BckupSet}->{$BckupKey} = $BckupVal;
print "$BckupKey=$BckupVal\n" if debug;
}
Чтобы сохранить все ошибки, вам нужно будет относиться к этому хэш-слоту в качестве ссылки на массив:
if ($line =~ m/(ERROR)[:=](.+)/){
my $BckupKey="8-Status";
my $BckupVal="Unsuccessful";
push @{ $MyItems{$ServerName}{$BckupSet}{$BckupKey} } => $BckupVal;
print "$BckupKey=$BckupVal\n" if debug;
}
В вашем сварении, 8-Status
Значения будут напоминать
«8-статус» => [«неудачно», «Другая ошибка», et CETERA '],
Если вы хотите зацикливаться на них позже, вы сделаете что-то вроде
foreach my $err (@{ $MyItems{$ServerName}{$BckupSet}{$BckupKey} }) {
print "got $err\n";
}
Чтобы получить только первый, вы пишете
print $MyItems{$ServerName}{$BckupSet}{$BckupKey}[0], "\n";
Еще одна проблема
foreach my $ServerName(@ARGV){
while (my $line = <>){
Представь это while (<>) { ... }
Неявно цикл по всем файлам, названным в @ARGV
, так встаивая его внутри петли @ARGV
не совсем имеет смысл. Если ваша командная строка имеет форму
$ readlogs server1 server2 server3 log1 log2
Тогда вы хотели бы сначала удалить из @ARGV
Серверы используют shift
. Отказ Отличительные аргументы Пользователь намерен, поскольку имена хостов сервера могут быть сложными. Одна конвенция использует --
Чтобы сигнализировать конец обработки опционов, чтобы вы могли
my @servers;
while (@ARGV) {
my $server = shift;
last if $server eq "--"
push @servers => $server;
}
die "Usage: $0 server .. -- log ..\n" unless @ARGV;
while (<>) {
# ...
}
Другие советы
Это не входит в тему, но в любое время, когда вам нужны глубоко вложенные структуры данных, ваш код работает на риск раздува и трудно читать. Простые удобные переменные проходят долгий путь к упорядочению вещей и освобождая читателя кода (вы, 3 месяца с данный момент), чтобы выполнить много умственных дифференциров:
# A convenience var.
my $bs = $MyItems{$ServerName}{$BckupSet};
# The rest of your code can use the var.
$bs->{'1-Server'} = $ServerName;
Кроме того, у вас есть несколько if
блоки, которые делают в основном то же самое. Кажется, поддается некоторой стратегии таблицы диспетчера:
my @dispatch_table = (
{
regex => qr/(backup-date)[:=](.+)/,
key => '4-DateStamp',
val => sub { $2 },
},
{
# etc.
},
);
Тогда твой if
Блоки отварить до чего-то вроде этого:
for my $dt (@dispatch_table){
next unless $line =~ $dt->{regex};
$bs->{ $dt->{key} } = $dt->{val}->();
}