【问题标题】:help printing out hash keys to needed format帮助打印出所需格式的哈希键
【发布时间】:2023-04-09 09:32:01
【问题描述】:

我需要帮助将数据从散列/散列引用打印到 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

刚刚添加(2010 年 8 月 7 日): 我正在使用的示例原始日志文件:(最近添加以更好地表示源日志)

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

【问题讨论】:

  • 设置词汇$ARGV 让我很紧张。你这样做有理由吗? $ARGV 是一个特殊变量,其中包含 &lt;&gt; 正在读取的文件的名称。设置它,更不用说将它声明为词法,这似乎是自找麻烦。
  • @daotoad - 这与我发布的另一个问题有关。 stackoverflow.com/questions/3427528/… 我需要传入超过 (1) 个日志文件。

标签: regex perl hash hash-of-hashes


【解决方案1】:

未经测试,但理论上应该可以工作。这将为主 MyItems 哈希的每个键打印一个输出行。如果您想将所有内容放在一行中,则可以删除 \n 或添加其他分隔符。

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

【讨论】:

  • 您是否收到错误消息?我测试了它,我得到了预期的输出。您应该将其与现有代码结合使用。抱歉,如果不清楚。用我拥有的替换 Dumper() 调用。
  • @Cfreak - 是的,错误。我什至尝试只打印一个,但没有运气。 ErrorMesg:在 ./hashtst2.pl 第 56 行使用“strict subs”时不允许裸词“backup”。在 ./hashtst2.pl 第 56 行使用“strict subs”时不允许裸词“backup”。裸词“status”在 ./hashtst2.pl 第 56 行使用“strict subs”时不允许。我编辑了代码以显示包括变量在内的整个脚本。
  • 只需引用 backup-timebackup-status
  • @Pedro - 谢谢,我引用了它。现在没有错误,但仍然没有输出:-(我的哈希是否正确?如果转储器正在显示数据,一定是这样。
  • 你用的是什么版本的 perl?
【解决方案2】:

我花了一些时间查看您的代码,我想我已经弄明白了。

这很难回答的原因是您无意中植入了一条红鲱鱼 - 数据转储器输出。

注意它如何显示$VAR1 = 'server1';,然后是$VAR2 = { blah };

你这样称呼 Dumper:print Dumper %MyItems;

问题是 Dumper 想要一个值列表来转储,因为 Perl 会扁平化列表,复杂的结构必须通过引用传递。所以,你需要像这样调用 Dumper:

print Dumper \%MyItems;

这显示了整个结构。

当您之前调用 dumper 时,您无意中剥离了一层数据结构。建议的解决方案和您自己的代码正在这个剥离的结构上运行。

在这里,我添加了一些代码来处理额外的嵌套层(并使其与 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";
    }
}

您似乎有很多问题,需要一些帮助来理解一些概念。我建议您在 Seekers of Perl Wisdom 中的 Perlmonks 上发布请求,以帮助改进您的代码。 SO 非常适合重点问题,但 PM 更适合代码返工。

** 原答案:**

为了解决我无法复制的任何解析问题,我只是将%MyItems 设置为您提供的 Dumper 的输出。

您上面提到的警告与您在打印语句中的所有复杂引用和重复编码有关。我已将您的打印语句替换为 map 以简化代码。

废话,一个大的连接地图等等并不简单,你可能在想。但实际上,它更简单,因为每个单独的表达单元都更小。什么更容易理解和正确?在正确和一致的庄园中,什么更容易改变和维护?

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

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

}

【讨论】:

  • @daotoad - 感谢您的意见。不,除了我从这个论坛收到的建议外,没有其他原因。我是编程和使用 perl 的新手。所以对我来说最佳实践会有所帮助。
  • @daotoad - 我在我要收集数据集的问题中添加了一个日志文件样本。它使用正则表达式来填充哈希。作为 perl 的新手,我对哪个更好用(数组或散列,散列的散列)感到困惑。就个人而言,干净的视觉表示会有所帮助。如果您能提供适合我技能水平的最佳方法,我将不胜感激。谢谢!!
  • @daotoad - 不幸的是,我正在运行 perl 5.8 :-( 找不到 feature.pm
  • feature 是 Perl 5.10 plus 的一部分。
  • @daotoad- 非常感谢您的意见。我正在努力学习这门语言,并会听取您的建议。是的,我使用这个语句来打印转储程序:'print Dumper(%MyItems);'感谢您的螺栓解决方案。我会测试一下,让你知道它是怎么回事。
【解决方案3】:

没有回答你提出的问题,但这对我来说似乎不明智。

你想要一个哈希数组而不是哈希哈希。

哈希没有排序,如果你想让它们排序然后使用数组。

【讨论】:

    【解决方案4】:

    感谢大家的帮助... 这对我有用。

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

    【讨论】:

      猜你喜欢
      • 2011-10-27
      • 1970-01-01
      • 2015-11-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-20
      • 1970-01-01
      相关资源
      最近更新 更多