Domanda

Ho bisogno di aiuto per stampare i dati da un arbitro hash/hash a stdout o file con dati in un ordine specifico, se possibile.

Ho una routine Perl che utilizza riferimenti hash in questo modo:

#!/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";
}

Output utilizzando 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'
                              }
        };

Output formattato che vorrei vedere:

MyHost=>server1;MyLogdate=>Fri Aug 06 2010;MyDataset=>abc2.cfl.mil.mad;backup-time=>Fri Aug 06 2010;backup-status=>Backup succeeded

Appena aggiunto (8/7/2010):File di registro non elaborato di esempio che sto utilizzando:(aggiunto di recente per fornire una migliore rappresentazione del registro di origine)

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
È stato utile?

Soluzione 4

Grazie a tutti per pitching in loro aiuto ... Questo funziona per me.

  for my $Server(keys%MyItems){
    for my $BckupSet(keys%{$MyItems{$Server}}){
      for(sort keys%{$MyItems{$Server}{$BckupSet}}){
        print$_,'=>',$MyItems{$Server}{$BckupSet}{$_},';';
      }
      print"\n";
    }
  }

Altri suggerimenti

Ho passato un po' di tempo a guardare il tuo codice e penso di averlo capito.

Il motivo per cui è difficile rispondere è che hai involontariamente piantato una falsa pista: l'output del dumper dei dati.

Nota come appare $VAR1 = 'server1'; poi $VAR2 = { blah };.

Hai chiamato Dumper in questo modo: print Dumper %MyItems;

Il problema è che Dumper vuole un elenco di valori da scaricare, poiché Perl appiattisce gli elenchi, le strutture complesse devono essere passate per riferimento.Quindi, devi chiamare Dumper in questo modo:

print Dumper \%MyItems;

Questo mostra l'intera struttura.

Quando hai chiamato dumper in precedenza, hai inavvertitamente rimosso uno strato della struttura dei dati.Le soluzioni proposte e il tuo codice operano su questa struttura ridotta.

Qui ho inserito del codice per gestire un ulteriore livello di nidificazione (e renderlo compatibile con Perl 5.8):

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";
    }
}

Sembra che tu abbia molte domande e abbia bisogno di aiuto per comprendere una serie di concetti.Ti suggerisco di pubblicare una richiesta su Perlmonks in Seekers of Perl Wisdom per chiedere aiuto per migliorare il tuo codice.SO è ottimo per domande mirate, ma PM è più suscettibile alla rielaborazione del codice.

** Risposta originale:**

Per aggirare eventuali problemi di analisi che non riesco a replicare, ho semplicemente impostato %MyItems all'output di Dumper che hai fornito.

Gli avvertimenti che hai menzionato sopra hanno a che fare con tutte le citazioni complicate e la codifica ripetitiva che hai nella tua dichiarazione stampata.Ho sostituito la tua dichiarazione print con a map per semplificare il codice.

Santo cielo, una grande mappa di unione blah non è più semplice, potresti pensare.Ma in realtà è più semplice perché ogni singola unità di espressione è più piccola.Cosa è più facile da capire e da ottenere bene?Cosa è più facile da modificare e mantenere in un maniero corretto e coerente?

print "'foo'=>$_->{foo};'bar'=>$_->{bar};boo'=>$_->{boo};'far'=>$_->{far}\n";

O

say join ';', map {
    "'$_'=>$item->{$_}"
} qw( foo bar boo far );

Qui puoi aggiungere, rimuovere o riorganizzare il tuo output semplicemente modificando l'elenco degli argomenti passati a map.Con l'altro stile, hai un sacco di copia/incolla da fare.

La mappa che utilizzo di seguito è un po' più complessa, in quanto controlla se una determinata chiave è definita prima di stampare un valore e assegna un valore predefinito se non ne è presente nessuno.

#!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 );

}

Non testato ma dovrebbe funzionare in teoria. Questo stamperà una linea di uscita per ciascuna delle chiavi per la MyItems principale hash. Se si desidera che tutto su una riga si può solo cadere il \ n o aggiungere qualche altro separatore.

foreach( values %MyItems ) {
     print "MyServer=>$_->{MyServer};MyLogdate=>$_->{MyLogdate};MyDataset=>$_->{MyDataset};backup-time=>$_->{backup-time};backup-status=>$_->{backup-status}\n";
}

Non rispondendo alla domanda che hai chiesto, ma questo non sembra ragionevole per me.

Si desidera un array di hash non un hash di hash.

Gli hash non sono ordinate, se si desidera che li ha ordinato quindi utilizzare un array.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top