perl - Hilfe bei der Hash-und Dumping von Datensätzen
-
30-09-2019 - |
Frage
ich ein Perl-Skript, das nur die letzte Gruppe von Datensätzen für einen benannten Satz zu halten, und ich habe mehr als einen Satz von Datensätzen. So ist es über die Daten in der Hash-Schreiben und nur den letzten Satz zu halten. Ich muss in den Ausdruck alle Datensätze helfen. Dank!
Hier ist eine Kopie meines Skript:
#!/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
Hier ist, wie es aussieht, wenn es Dumps:
$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'
}
}
};
Lösung
Auf der Grundlage der Debug-Ausgabe, es sieht aus wie Ihr Problem ist hier:
if ($line =~ m/(ERROR)[:=](.+)/){
my $BckupKey="8-Status";
my $BckupVal="Unsuccessful";
$MyItems{$ServerName}{$BckupSet}->{$BckupKey} = $BckupVal;
print "$BckupKey=$BckupVal\n" if debug;
}
Um alle Fehler zu speichern, müssen Sie diesen Hash-Slot als Referenz auf ein Array behandeln:
if ($line =~ m/(ERROR)[:=](.+)/){
my $BckupKey="8-Status";
my $BckupVal="Unsuccessful";
push @{ $MyItems{$ServerName}{$BckupSet}{$BckupKey} } => $BckupVal;
print "$BckupKey=$BckupVal\n" if debug;
}
In Ihrem dump, die 8-Status
Werte ähneln
'8-Status' => [ 'Unsuccessful', 'Other error', 'Et cetera' ],
Wenn Sie über sie später Schleife wollen, würden Sie tun so etwas wie
foreach my $err (@{ $MyItems{$ServerName}{$BckupSet}{$BckupKey} }) {
print "got $err\n";
}
Um nur die erste, würden Sie schreiben
print $MyItems{$ServerName}{$BckupSet}{$BckupKey}[0], "\n";
Ein weiteres Problem ist
foreach my $ServerName(@ARGV){
while (my $line = <>){
Erkennen, dass while (<>) { ... }
Schleifen über implizit alle in @ARGV
benannten Dateien, so dass es in einer Schleife über @ARGV
nistet nicht ganz sinnvoll. Wenn Ihre Befehlszeile ist von der Form
$ readlogs server1 server2 server3 log1 log2
dann würden Sie zuerst entfernen möchten aus @ARGV
den Servern mit shift
. Erkennungsmerkmal Argumente der Benutzer als Server Host-Name beabsichtigt könnte schwierig sein. Eine Konvention wird mit --
das Ende der Option auf die Signalverarbeitung, so dass Sie möglicherweise
my @servers;
while (@ARGV) {
my $server = shift;
last if $server eq "--"
push @servers => $server;
}
die "Usage: $0 server .. -- log ..\n" unless @ARGV;
while (<>) {
# ...
}
Andere Tipps
Dies ist off topic, aber jedes Mal müssen Sie tief verschachtelte Datenstrukturen Code läuft ein Risiko, aufgebläht und schwer zu lesen. Einfache Bequemlichkeit Variablen geht einem langen Weg in Richtung Dinge zu straffen und den Leser des Codes entlastet (Sie, 3 Monate ab jetzt) ??viele psychischen diffs durchführen zu müssen:
# A convenience var.
my $bs = $MyItems{$ServerName}{$BckupSet};
# The rest of your code can use the var.
$bs->{'1-Server'} = $ServerName;
Außerdem haben Sie mehr if
Blöcke bekommen, das im Grunde das gleiche tun. Scheint eine Art Dispatch-Tabelle Strategie zugänglich:
my @dispatch_table = (
{
regex => qr/(backup-date)[:=](.+)/,
key => '4-DateStamp',
val => sub { $2 },
},
{
# etc.
},
);
Dann wird Ihr if
Blöcke einkochen zu so etwas wie folgt aus:
for my $dt (@dispatch_table){
next unless $line =~ $dt->{regex};
$bs->{ $dt->{key} } = $dt->{val}->();
}