arrays - Perl在输入条件之前更改条件内的值?

标签 arrays perl hashmap conditional-statements

我正在编写一个 Perl 脚本,以帮助自动扫描我们网络上的机器。我不是专业的程序员,但是这个项目已经分配给了我,我很困惑。在我解释困扰我的事情的性质之前,让我解释一下我正在做的事情的大纲。

基本上,此脚本将每 n 小时运行一次。运行时,它将检查一个包含事件 IP 日志的文件,并根据 DHCP 日志检查它们以仅挑选出那些是静态的。然后将它们放入哈希中(如果标记为初始化,则使用新的,否则使用 Storable 加载), key 是 IP,在数组中它们的 MAC [0] 和“最后扫描”日期 [1] 最初设置为19700101。脚本的下一部分比较今天日期和“上次扫描”日期之间的日期 - 如果它低于某个阈值,它会向我们的扫描仪发送查询。

让我如此迷失的问题是,在检查日期时,在我看来,日期值(更新的“上次扫描”)是在输入条件之前设置的。虽然这对我来说似乎不太可能,但这是我能想到的唯一可能性。以下是相关的代码块:

将 IP/MAC 添加到哈希的代码

 if(init == 1){
            %SCAN = ();

            @data = ();

            foreach $key (keys %IPS){

                    $unsavedDB = 1;

                    $data[0] = $IPS{$key};
                    $data[1] = 19700101;

                    print $data[1];

                    $SCAN{$key} = \@data;
            }
 }else{
            #repeat of the above code, but with a if(exists...) to prevent duplicates from being added to the hash that is loaded via storables.
 }

检查日期的代码(之前设置的,今天是 20120726)。在上面的代码和下面的代码之间只有注释
    $scanned = 0;

    foreach $key (keys %SCAN){

            $lastScanned = $SCAN{$key}[1];

            if(($date - $lastScanned) > $threshold){
                    $unsavedDB = 1;

                    $toScan = ${$key}[0];

                    #omitted data for security reasons, just basically forms a string to send to a scanner

                    $SCAN{$key}[1] = $date;

                    $scanned++;
            }
    }

    print "finished. $scanned hosts queued\n";

现在,我相信在进入循环之前值被更改的原因是当我在“if(($date ...){”之前添加一个“print $lastScanned”语句时,打印了分配的任何内容的日期到 $date 之前 - 但是如果我注释掉 '$SCAN{$key}[1] = $date;' 语句,打印语句将打印 '19700101' 日期并且一切正常运行。发生了什么? $SCAN{$key}[1] 除了上面显示的两个地方外,永远不会被触及。

对不起,如果这措辞很糟糕,或者没有意义。我尽力解释了困扰我几个小时的事情。

谢谢!

最佳答案

因为您的@data数组是全局的,每次执行语句时

$SCAN{$key} = \@data;

你分配给 $SCAN{$key}引用相同的@data大批。因此,%SCAN 中的所有值最终指向同一个数组,这可能不是你想要的。

有几种方法可以解决这个问题。也许最简单的方法是让代码为 @data 的副本分配一个引用。数组到 $SCAN{$key} ,通过将上面的行更改为
$SCAN{$key} = [ @data ];

或者,您可以重写整个循环以使用用 my 声明的词法数组。在循环内部——这样你就可以在每次迭代时创建一个新的单独数组:
foreach $key (keys %IPS) {
        $unsavedDB = 1;

        my @data;  # <--- this line is new!

        $data[0] = $IPS{$key};
        $data[1] = 19700101;

        print $data[1];

        $SCAN{$key} = \@data;
}

然而,你真正应该做的是学习how variable scoping works in Perl,而不是仅仅修复这个特定错误的症状。以及应该如何使用它,并相应地重写您的代码。

特别是,查看您的代码,我非常怀疑您没有使用 the strict pragma在你的代码中。如果您想编写干净的 Perl 代码,您真正应该做的第一件事是在所有脚本前添加以下两行,紧跟在 #! 之后。线:
use strict;
use warnings;
strict pragma 强制您避免某些不良和容易出错的习惯,例如使用符号引用或未声明的全局变量,而 the warnings pragma让解释器警告您有关其他各种愚蠢、风险、模棱两可或其他不受欢迎的事情(您确实应该将其视为错误并修复,直到您不再收到警告为止)。

当然,这并不意味着您应该在脚本开头使用 my 声明所有变量。 (或 our )只是为了制作 strict快乐的。相反,您应该做的是查看每个变量,查看它实际使用的位置,并在需要它的最内层范围内声明它。(如果您在代码的不同部分重用相同的变量名,请将它们视为单独的变量并分别声明它们。)请记住,您可以在循环语句中声明循环变量,如
foreach my $key (keys %IPS) {

或者
while (my $line = <>) {

附言。我还注意到您向我们展示的代码中有一条令人担忧的评论:
# repeat of the above code, but with ...

一般来说,这种代码重复应该是一个很大的闪烁信号,表明你可能做错了什么——编程的黄金法则是“Don't repeat yourself.

当然,在极少数非常罕见的情况下,您确实需要以两种不同的方式完成本质上相同的事情,但有如此多的小而随意的差异贯穿其中,因此将整个事情写两次会更清晰。但如果是这种情况,我会感到非常惊讶——我敢打赌,你只能编写该代码一次,然后插入一个
if (not $init and exists ...) {

在合适的位置检查。

关于arrays - Perl在输入条件之前更改条件内的值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11678666/

相关文章:

python - 为什么 python 列表比 numpy 数组能容纳更多数据?

c - C中的字符串数组非常困惑

perl - 如何在 Perl 中获取相关的 t 统计量和 p 值?

java - 从接口(interface)集中删除全部

java - HashMap 返回 NULL

java - 按列将数据添加到二维数组中

perl - 在 perl 中将系统日期转换为 iso 8601 格式

MySQL 插入不存在的地方不起作用

c - 5000以下整数的哈希函数?

c# - 通过数组传递给构造函数