Perl - ayuda de almohadilla y el vertido de los registros
-
30-09-2019 - |
Pregunta
tengo un script en perl que sólo se mantiene el último conjunto de registros para un conjunto con nombre y tengo más de un conjunto de registros. Por lo que su sobre escribir los datos en el hash y sólo mantener la última serie. Necesito ayuda para la hora de imprimir todos los registros. Gracias!
Aquí está una copia de mi script:
#!/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
Esto es lo que parece cuando se vuelca:
$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'
}
}
};
Solución
Con base en el resultado de la depuración, parece que el problema está aquí:
if ($line =~ m/(ERROR)[:=](.+)/){
my $BckupKey="8-Status";
my $BckupVal="Unsuccessful";
$MyItems{$ServerName}{$BckupSet}->{$BckupKey} = $BckupVal;
print "$BckupKey=$BckupVal\n" if debug;
}
Para guardar todos los errores, que necesitará para tratar esa ranura de hash como una referencia a un array:
if ($line =~ m/(ERROR)[:=](.+)/){
my $BckupKey="8-Status";
my $BckupVal="Unsuccessful";
push @{ $MyItems{$ServerName}{$BckupSet}{$BckupKey} } => $BckupVal;
print "$BckupKey=$BckupVal\n" if debug;
}
En el vertedero, los valores 8-Status
se parecerán
'8-Status' => [ 'Unsuccessful', 'Other error', 'Et cetera' ],
Si desea bucle sobre ellos más adelante, que harías algo así como
foreach my $err (@{ $MyItems{$ServerName}{$BckupSet}{$BckupKey} }) {
print "got $err\n";
}
Para obtener únicamente la primera, que iba a escribir
print $MyItems{$ServerName}{$BckupSet}{$BckupKey}[0], "\n";
Otra cuestión es
foreach my $ServerName(@ARGV){
while (my $line = <>){
Date cuenta de que while (<>) { ... }
bucles de forma implícita sobre todos los archivos denominados en @ARGV
, por lo que anidan dentro de un bucle sobre @ARGV
no acaba de tener sentido. Si su línea de comandos es de la forma
$ readlogs server1 server2 server3 log1 log2
entonces querría primero retire de @ARGV
los servidores utilizando shift
. Distinguir los argumentos que el usuario tiene la intención como nombres de host de servidor podría ser complicado. Una convención está utilizando --
para indicar el final del procesamiento de las opciones, por lo que podría
my @servers;
while (@ARGV) {
my $server = shift;
last if $server eq "--"
push @servers => $server;
}
die "Usage: $0 server .. -- log ..\n" unless @ARGV;
while (<>) {
# ...
}
Otros consejos
Esto es fuera de tema, pero cada vez que necesite profundamente las estructuras de datos anidadas su código corre el riesgo de convertirse en hinchada y difícil de leer. las variables de conveniencia simples recorrer un largo camino hacia la racionalización de las cosas y aliviar el lector del código (que, de 3 meses a partir de ahora) de tener que realizar muchas diferenciaciones mentales:
# A convenience var.
my $bs = $MyItems{$ServerName}{$BckupSet};
# The rest of your code can use the var.
$bs->{'1-Server'} = $ServerName;
Además, usted tiene varios bloques if
que hacen básicamente lo mismo. Parece susceptible de algún tipo de estrategia de mesa de despacho:
my @dispatch_table = (
{
regex => qr/(backup-date)[:=](.+)/,
key => '4-DateStamp',
val => sub { $2 },
},
{
# etc.
},
);
A continuación, sus bloques if
se reducen a algo como esto:
for my $dt (@dispatch_table){
next unless $line =~ $dt->{regex};
$bs->{ $dt->{key} } = $dt->{val}->();
}