помогите распечатать хэш-ключи в нужном формате

Мне нужна помощь в распечатке данных из хэша/хеш-ссылки в STDOUT или в файл с данными в определенном порядке, если это возможно.

У меня есть процедура Perl, которая использует хэш-ссылки, например:

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

Вывод с помощью дампера:

$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'
                              }
        };

Формат вывода, который я хотел бы видеть:

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

Только что добавлено (07.08.2010): Образец необработанного файла журнала, который я использую: (недавно добавлен для лучшего представления исходного журнала)

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

person jdamae    schedule 07.08.2010    source источник
comment
Установка лексического $ARGV заставляет меня нервничать. Есть ли причина, по которой вы это делаете? $ARGV — это специальная переменная, содержащая имя файла, из которого <> читает. Установка его, не говоря уже о том, чтобы объявить его лексическим, кажется напрашивающимся на неприятности.   -  person daotoad    schedule 07.08.2010
comment
@daotoad - это было связано с другим вопросом, который я разместил. stackoverflow.com/questions/3427528/ Мне нужно будет передать чтение более чем (1) файлу журнала.   -  person jdamae    schedule 07.08.2010


Ответы (4)


Я потратил некоторое время на просмотр вашего кода, и я думаю, что понял его.

Причина, по которой на этот вопрос было трудно ответить, заключается в том, что вы непреднамеренно подбросили отвлекающий маневр — выходные данные дампа данных.

Обратите внимание, как он показывает $VAR1 = 'server1';, а затем $VAR2 = { blah };.

Вы назвали Дампера так: print Dumper %MyItems;

Проблема в том, что Dumper хочет выгрузить список значений, поскольку Perl сглаживает списки, сложные структуры должны передаваться по ссылке. Итак, вам нужно вызвать Dumper следующим образом:

print Dumper \%MyItems;

Это показывает всю структуру.

Когда вы ранее вызывали дампер, вы непреднамеренно удалили один слой вашей структуры данных. Предлагаемые решения и ваш собственный код работают с этой урезанной структурой.

Здесь я добавил некоторый код для обработки дополнительного уровня вложенности (и сделал его совместимым с 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";
    }
}

Похоже, у вас много вопросов и вам нужна помощь, чтобы разобраться в некоторых концепциях. Я предлагаю вам разместить запрос на Perlmonks в Seekers of Perl Wisdom для помощи в улучшении вашего кода. SO отлично подходит для сфокусированных вопросов, но PM больше подходит для переделки кода.

** Исходный ответ: **

Чтобы обойти любые проблемы синтаксического анализа, которые я не могу воспроизвести, я просто установил %MyItems для вывода Dumper, который вы предоставили.

Ваши предупреждения, о которых вы упоминали выше, связаны со всеми сложными цитированием и повторяющимся кодом, который вы имеете в своем заявлении о печати. Я заменил ваш оператор печати на map, чтобы упростить код.

Святое дерьмо, большая карта соединений не проще, может быть, вы думаете. Но на самом деле это проще, потому что каждая отдельная единица выражения меньше. Что легче понять и понять? Что легче переделать и сохранить в правильном и последовательном поместье?

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

or

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

Здесь вы можете добавлять, удалять или изменять порядок вывода, просто изменяя список аргументов, передаваемых в map. С другим стилем у вас есть куча операций копирования/вставки.

Карта, которую я использую ниже, немного сложнее, поскольку она проверяет, определен ли данный ключ перед печатью значения, и присваивает значение по умолчанию, если его нет.

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

}
person daotoad    schedule 07.08.2010
comment
@daotoad - Спасибо за ваш вклад. Нет, нет никаких причин, кроме предложений, которые я взял с этого форума. Я новичок в программировании и использовании Perl. Поэтому лучшие практики для меня были бы полезны. - person jdamae; 07.08.2010
comment
@daotoad - я добавил образец файла журнала в свой вопрос, через который я собираюсь собрать свой набор данных. Он использует регулярное выражение для заполнения хеша. Будучи новичком в Perl, я сбиваюсь с толку, что лучше использовать (массив или хеш, хэш хэшей). Лично мне помогает чистое визуальное представление. Если вы можете предложить лучший подход для моего уровня навыков, который я могу использовать, буду признателен. Благодарность!! - person jdamae; 07.08.2010
comment
@daotoad - к ​​сожалению, я использую Perl 5.8 :-( Не могу найти feature.pm - person jdamae; 07.08.2010
comment
feature является частью Perl 5.10 плюс. - person daotoad; 07.08.2010
comment
@daotoad- большое спасибо за ваш вклад. Я пытаюсь выучить этот язык и прислушаюсь к вашему совету. Да, я использовал этот оператор для печати дампера: 'print Dumper(%MyItems);' Спасибо за ваше болтовое решение. Я проверю это и дам вам знать, как это происходит. - person jdamae; 08.08.2010

Не проверял, но в теории должно работать. Это напечатает строку вывода для каждого из ключей основного хэша MyItems. Если вы хотите, чтобы все это было в одной строке, вы можете просто убрать \n или добавить другой разделитель.

foreach( values %MyItems ) {
     print "MyServer=>$_->{MyServer};MyLogdate=>$_->{MyLogdate};MyDataset=>$_->{MyDataset};backup-time=>$_->{backup-time};backup-status=>$_->{backup-status}\n";
}
person Cfreak    schedule 07.08.2010
comment
Вы получаете ошибку? Я протестировал его и получил ожидаемый результат. Вы должны использовать это в сочетании с вашим существующим кодом. Извините, если это было непонятно. Замените вызов Dumper() тем, что у меня есть. - person Cfreak; 07.08.2010
comment
@Cfreak - Да, ошибка. Я даже пытался просто распечатать один из них, и мне не повезло. ErrorMesg: резервное копирование голого слова не разрешено, пока используются строгие подписки в ./hashtst2.pl, строка 56. Резервное копирование голого слова не разрешено, пока используются строгие подписки в ./hashtst2.pl, строка 56. Состояние голого слова не разрешено, пока используются строгие подписки в ./ hashtst2.pl строка 56. Я отредактировал код, чтобы показать весь скрипт, включая переменные. - person jdamae; 07.08.2010
comment
просто процитируйте backup-time и backup-status. - person Pedro Silva; 07.08.2010
comment
@ Педро - спасибо, я процитировал это. Ошибок теперь нет, но по-прежнему нет вывода :-( Мой хэш правильный? Должно быть, если дамп показывает данные. - person jdamae; 07.08.2010
comment
какую версию перла вы используете? - person Cfreak; 08.08.2010

Не отвечая на вопрос, который вы задали, но это не кажется мне разумным.

Вам нужен массив хэшей, а не хэш хэшей.

Хэши не упорядочены, если вы хотите, чтобы они были упорядочены, используйте массив.

person Paul Hutchinson    schedule 07.08.2010

Спасибо всем за помощь... Это работает для меня.

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