ajuda a impressão de chaves de hash para o formato necessário
-
26-09-2019 - |
Pergunta
Preciso de ajuda para imprimir dados a partir de um hash/hash ref para STDOUT ou um ficheiro com dados em uma ordem específica, se possível.
Eu tenho um perl de rotina que usa o hash de referências, como por exemplo:
#!/usr/local/bin/perl
use strict;
use warnings;
use File::Basename;
use Data::Dumper;
my %MyItems;
my $ARGV ="/var/logdir/server1.log";
my $mon = 'Aug';
my $day = '06';
my $year = '2010';
while (my $line = <>)
{
chomp $line;
if ($line =~ m/(.* $mon $day) \d{2}:\d{2}:\d{2} $year: ([^:]+):backup:/)
{
my $server = basename $ARGV, '.log';
my $BckupDate="$1 $year";
my $BckupSet =$2;
$MyItems{$server}{$BckupSet}->{'MyLogdate'} = $BckupDate;
$MyItems{$server}{$BckupSet}->{'MyDataset'} = $BckupSet;
$MyItems{$server}{$BckupSet}->{'MyHost'} = $server;
if ($line =~ m/(ERROR|backup-size|backup-time|backup-status)[:=](.+)/)
{
my $BckupKey=$1;
my $BckupVal=$2;
$MyItems{$server}{$BckupSet}->{$BckupKey} = $BckupVal;
}
}
}
foreach( values %MyItems ) {
print "MyHost=>$_->{MyHost};MyLogdate=>$_->{MyLogdate};MyDataset=>$_->{MyDataset};'backup-time'=>$_->{'backup-time'};'backup-status'=>$_->{'backup-status'}\n";
}
Saída usando dumper:
$VAR1 = 'server1';
$VAR2 = {
'abc1.mil.mad' => {
'ERROR' => ' If you are sure is not running, please remove the file and restart ',
'MyLogdate' => 'Fri Aug 06 2010',
'MyHost' => 'server1',
'MyDataset' => 'abc1.mil.mad'
},
'abc2.cfl.mil.mad' => {
'backup-size' => '187.24 GB',
'MyLogdate' => 'Fri Aug 06 2010',
'MyHost' => 'server1',
'backup-status' => 'Backup succeeded',
'backup-time' => '01:54:27',
'MyDataset' => 'abc2.cfl.mil.mad'
},
'abc4.mad_lvm' => {
'backup-size' => '422.99 GB',
'MyLogdate' => 'Fri Aug 06 2010',
'MyHost' => 'server1',
'backup-status' => 'Backup succeeded',
'backup-time' => '04:48:50',
'MyDataset' => 'abc4.mad_lvm'
}
};
Saída formatada que eu gostaria de ver:
MyHost=>server1;MyLogdate=>Fri Aug 06 2010;MyDataset=>abc2.cfl.mil.mad;backup-time=>Fri Aug 06 2010;backup-status=>Backup succeeded
Apenas addded (8/7/2010):Exemplo de matérias arquivo de log que eu estou usando:(recentemente adicionado para proporcionar uma melhor representação do log de origem)
Fri Aug 06 00:00:05 2010: abc2.cfl.mil.mad:backup:INFO: backup-set=abc2.cfl.mil.mad
Fri Aug 06 00:00:05 2010: abc2.cfl.mil.mad:backup:INFO: backup-date=20100806000004
Fri Aug 06 00:48:54 2010: abc4.mad_lvm:backup:INFO: backup-size=422.99 GB
Fri Aug 06 00:48:54 2010: abc4.mad_lvm:backup:INFO: PHASE END: Calculating backup size & checksums
Fri Aug 06 00:48:54 2010: abc4.mad_lvm:backup:INFO: backup-time=04:48:50
Fri Aug 06 00:48:54 2010: abc4.mad_lvm:backup:INFO: backup-status=Backup succeeded
Fri Aug 06 00:48:54 2010: abc4.mad_lvm:backup:INFO: Backup succeeded
Solução 4
Obrigado a todos por lançarem sua ajuda ... isso funciona para mim.
for my $Server(keys%MyItems){
for my $BckupSet(keys%{$MyItems{$Server}}){
for(sort keys%{$MyItems{$Server}{$BckupSet}}){
print$_,'=>',$MyItems{$Server}{$BckupSet}{$_},';';
}
print"\n";
}
}
Outras dicas
Eu passei algum tempo a olhar para o seu código e eu acho que eu tenha imaginado.
O motivo foi difícil a resposta é que você, inadvertidamente, plantou um arenque vermelho--os dados dumper de saída.
Observe como ele mostra $VAR1 = 'server1';
e, em seguida, $VAR2 = { blah };
.
Você chamou Dumper assim: print Dumper %MyItems;
O problema é que Dumper quer uma lista de valores de despejo, uma vez que o Perl achata listas, estruturas complexas devem ser passados por referência.Então, você precisa chamar o Dumper assim:
print Dumper \%MyItems;
Isso mostra toda a estrutura.
Quando você chamou dumper anterior, você inadvertidamente retirado, uma camada de sua estrutura de dados.As soluções propostas, e o seu próprio código estão operando neste despojado estrutura.
Aqui eu trancada em algum código para lidar com camada adicional de otimização (e fez Perl 5.8 compatível):
for my $server_items ( values %MyItems ) {
for my $record ( values %$server_items ) {
print join ';', map {
# Replace non-existant values with 'undef'
my $val = exists $record->{$_} ? $record->{$_} : 'undef';
"'$_'=>$val" # <-- this is what we print for each field
} qw( MyHost MyLogdate MyDataset backup-time backup-status );
print "\n";
}
}
Parece que você tem um monte de perguntas e precisa de alguma ajuda para a obtenção de sua cabeça em torno de uma série de conceitos.Eu sugiro que você postar um pedido de Perlmonks em Requerentes de Perl Sabedoria para ajudar a melhorar o seu código.ENTÃO é ótimo para centrou a questão, mas a PM é mais passível de código de retrabalho.
** Originais resposta:**
Para contornar qualquer análise de problemas que eu não posso replicar, eu apenas definir %MyItems
para a saída do Dumper que você forneceu.
Seus avisos de que você menciona acima tem a ver com tudo o complicado cotação e repetitivos de codificação que você tem em sua instrução de impressão.Eu ter substituído a sua instrução de impressão com um map
para simplificar o código.
Holy crap, uma grande associação mapa blá não é mais simples, você pode estar pensando.Mas realmente, ele é mais simples, porque cada unidade individual de expressão é menor.O que é mais fácil para compreender e obter certo?O que é mais fácil para alterar e manter um uso correcto e consistente de manor?
print "'foo'=>$_->{foo};'bar'=>$_->{bar};boo'=>$_->{boo};'far'=>$_->{far}\n";
ou
say join ';', map {
"'$_'=>$item->{$_}"
} qw( foo bar boo far );
Aqui, você pode adicionar, remover ou reorganizar a sua saída apenas alterando a lista de argumentos passados para map
.Com o outro estilo, você tem um monte de copiar/colar para fazer.
O mapa que eu uso abaixo é um pouco mais complexo, em que ele verifica se uma dada chave está definido antes de imprimir um valor, e atribuir um valor padrão se nenhum estiver presente.
#!perl
use strict;
use warnings;
use feature 'say';
my %MyItems = (
'abc1.mil.mad' => {
'ERROR' => ' If you are sure is not running, please remove the file and restart ',
'MyLogdate' => 'Fri Aug 06 2010',
'MyHost' => 'server1',
'MyDataset' => 'abc1.mil.mad'
},
'abc2.cfl.mil.mad' => {
'backup-size' => '187.24 GB',
'MyLogdate' => 'Fri Aug 06 2010',
'MyHost' => 'server1',
'backup-status' => 'Backup succeeded',
'backup-time' => '01:54:27',
'MyDataset' => 'abc2.cfl.mil.mad'
},
'abc3.mil.mad' => {
'backup-size' => '46.07 GB',
'MyLogdate' => 'Fri Aug 06 2010',
'MyHost' => 'server1',
'backup-status' => 'Backup succeeded',
'backup-time' => '00:41:06',
'MyDataset' => 'abc3.mil.mad'
},
'abc4.mad_lvm' => {
'backup-size' => '422.99 GB',
'MyLogdate' => 'Fri Aug 06 2010',
'MyHost' => 'server1',
'backup-status' => 'Backup succeeded',
'backup-time' => '04:48:50',
'MyDataset' => 'abc4.mad_lvm'
}
);
for my $record ( values %MyItems ) {
say join ';', map {
my $val = $record->{$_} // 'undef'; # defined-or requires perl 5.10 or newer.
"'$_'=>$val" # <-- this is what we print for each field
} qw( MyHost MyLogdate MyDataset backup-time backup-status );
}
Não testado, mas deve funcionar em teoria. Isso imprimirá uma linha de saída para cada uma das chaves para o hash principal do myitems. Se você quiser tudo em uma linha, basta soltar o n ou adicionar outro separador.
foreach( values %MyItems ) {
print "MyServer=>$_->{MyServer};MyLogdate=>$_->{MyLogdate};MyDataset=>$_->{MyDataset};backup-time=>$_->{backup-time};backup-status=>$_->{backup-status}\n";
}
Não respondendo à pergunta que você fez, mas isso não me parece sensato.
Você quer uma variedade de hashes e não um hash de hashes.
Os hashes não são encomendados, se você deseja que eles sejam encomendados, use uma matriz.