3

首先,如果我在即将发布的帖子中有任何术语错误,请原谅,这对我来说仍然很新。

一些背景知识,我有一个脚本可以检查我们存档的网络配置中的一组特定设置。因此,脚本会运行许多检查,并将结果添加到该检查的数组中。

例如,检查以确保配置 syslog 被添加到名为 @internalsyslogerror 的数组中

在所有检查都运行后,所有检查的数组都被添加到哈希中,键是设备名称。

注意所有代码都使用严格,使用警告

使用以下命令;

$results{$configs} = [@internalsyslogerror, @bordersyslogerror, 
@borderntperror, @borderntperror, @internalntperror, 
@bordertacacserror, @internaltacacserror, @enablepasswordchecks,
@internalsnmpkeyserror, @timezoneerror, @configregistererror, 
@bannererror, @bootregistererror, @domainnameerror];

我遇到的问题是提取此信息的最优雅的方式是什么,我想减少为了向脚本添加新检查而必须进行的更改量。目前我必须将附加数组添加到上面的代码中,然后将取消引用部分添加到处理它的子程序中。

这是目前我要取消引用并将其输出到数组中所做的工作,然后我会通过电子邮件发送该数组。

foreach my $k (keys %results) {
    push @results, "<b>$k</b><br>";
    if (defined $results{$k}[0] ){
    push @results, "$results{$k}[0]";
    }
    if (defined $results{$k}[1] ){
    push @results, "$results{$k}[1]";
    }
    if (defined $results{$k}[2] ){
    push @results, "$results{$k}[2]";
    }
    if (defined $results{$k}[3] ){  
    push @results, "$results{$k}[3]";
    }
    if (defined $results{$k}[4] ){
    push @results, "$results{$k}[4]";
    }
    if (defined $results{$k}[5] ){
    push @results, "$results{$k}[5]";
    }
    if (defined $results{$k}[6] ){
    push @results, "$results{$k}[6]";
    }
    if (defined $results{$k}[7] ){
    push @results, "$results{$k}[7]";
    }
    if (defined $results{$k}[8] ){
    push @results, "$results{$k}[8]";
    }
    if (defined $results{$k}[9] ){
    push @results, "$results{$k}[9]";
    }
    if (defined $results{$k}[10] ){
    push @results, "$results{$k}[10]";
    }
    if (defined $results{$k}[11] ){
    push @results, "$results{$k}[11]";
    }
    if (defined $results{$k}[12] ){
    push @results, "$results{$k}[12]";
    }
    if (defined $results{$k}[13] ){
    push @results, "$results{$k}[13]";
    }
}

问题是,我可以做我上面做的事情,但是以某种方式“即时”生成代码

谢谢

4

5 回答 5

5
foreach my $k (keys %results) { 
   push @results, "<b>$k</b><br>"; 
   for my $result (@{$results{$k}) {
       next if (!defined $result);
       push @results, $result;
   }
}

甚至

foreach my $k (keys %results) { 
   push @results, "<b>$k</b><br>"; 
   push @results, grep { defined $_ } @{$results{$k}};
}

编辑:修复了最后一次推送中的错字...

于 2011-06-21T10:32:46.160 回答
4

我还没有看到足够多的代码来确定此代码段不会改变现有行为。不过应该没问题。它肯定会提高可维护性:

foreach my $k (keys %results) {
    push @results, "<b>$k</b><br>";
    foreach my $index ( 0..$#{$results{$k}} ) {
        if (defined $results{$k}[$index] ){
            push @results, "$results{$k}[$index]";
        }
    }
}

以上替换了您的整个 foreach / if 构造。

于 2011-06-21T10:31:48.823 回答
3

使用 for 循环:

for ($i = 0; $i < 14; $i++) {
  ...
}
于 2011-06-21T10:13:32.417 回答
2

在我看来,这段代码是……功能失调。如果我错了,请纠正我。

$results{$configs} = [@internalsyslogerror, @bordersyslogerror, ... ];

这只会创建一个长的标量值数组,而不是一个数组数组。考虑一下:

C:\perl>perl -we "@a=qw(1 2 3 a); @g=(11,22,33,44); $b{key}=[@a,@g]; print qq(@{$b{key}},\n); print qq($b{key}[0]);"
1 2 3 a 11 22 33 44,
1

这清楚地表明$b{key}包含 和 的所有值,并且@a仅引用第一个数组中的第一个值,即。@g$b{key}[0]$a[0]

为了执行您似乎正在做的事情,即将日志收集到单独的变量中,在某个键下,您必须使用数组引用:

$results{$config} = [\@internalsyslogerror, \@bordersyslogerror, ...];

我可以看到您当前的解决方案有效的唯一方法是,如果您的代码中有一个错误/功能(有意或无意),每个数组中的第一个值包含与该类别相关的所有数据,例如:

$internalsyslogerror[0] = "device A not responding, shutting down.\ndevice A rebooted.\nyada yada\n ....";

如果是这种情况,那么您所做的就相当于:

$results{$config} = [ $internalsyslogerror[0], $bordersyslogerror[0], ...];

但是,如果您应该在其中一个数组中获得两个值,那么您的系统将被搞砸,并且您将在报告末尾出现一个错误的错误。除非您对值使用动态 for 循环,push否则它仍然会很混乱。

此外,通过排除未定义的值,您的内部结构(仅取决于顺序)将被搞砸,因此您将不知道第一个值是否@results来自@internalsyslogerroror @bordersyslogerror

结论:

如果您对当前系统运行良好感到满意,只需按照其他人的建议使用 for 循环。使用动态值而不是绝对值。我喜欢 FMc 的解决方案(略有改动):

# Solution by FMc
for my $k (keys %results) {
    push @results, "<b>$k</b><br>";
    push @results, grep { defined $results{$k}[$_] } 0 .. $#results{$k};
}

但是,如果要保留内部结构,则不能排除未定义的值,也不能将所有不同的数组合并为一个,除非数据已经在第一个数组值中加入字符串。所以:

$results{$config} = [ \@array1, \@array2, ...];

....

for my $key (keys %results) {
    push @results, "<b>$key</b><br>";
    my $i=0;
    for my $ref (@{$results{$key}]) {
        push @results, "Array $i:\n<br>" . (defined @$ref ? "@$ref" : "");
        $i++;
    }
}

输出的格式也可以微调。代替字符串连接,例如"@array",您可以进行显式连接:join("<br>\n", @array)

于 2011-06-21T11:11:51.883 回答
1

如果您没有对密钥执行任何操作,则这是等效的:

@results = map { "$_" } grep {; defined } map { @$_ } values %results;
于 2011-06-21T11:32:56.413 回答