另外使用未初始化的值$ 1 - Perl

时间:2012-02-08 15:32:34

标签: regex perl

我正在编写一个程序,它有点模仿UNIX中的最后一个命令,我试图在我的解决方案中使用反向引用。我的程序完全按照它应该做的但我得到运行时错误/警告。我的问题是为什么会出现此错误/警告,我该如何解决这样的问题?

如果您需要我可以提供的更多信息。

程序执行

./last dodoherty

输出

Here is a listing of the logins for dodoherty:

1. dodohert pts/1        pc-618-012.omhq. Wed Feb  8 09:19   still logged in
2. dodohert pts/6        ip98-168-203-118 Tue Feb  7 19:19 - 20:50  (01:31)
3. dodohert pts/3        137.48.207.178   Tue Feb  7 14:00 - 15:06  (01:05)
4. dodohert pts/1        137.48.219.250   Tue Feb  7 12:32 - 12:36  (00:04)
5. dodohert pts/21       137.48.207.237   Tue Feb  7 12:07 - 12:23  (00:16)
6. dodohert pts/11       ip98-168-203-118 Mon Feb  6 20:50 - 23:29  (02:39)
7. dodohert pts/9        ip98-168-203-118 Mon Feb  6 20:31 - 22:57  (02:26)
8. dodohert pts/5        pc-618-012.omhq. Fri Feb  3 10:24 - 10:30  (00:05)
Use of uninitialized value $1 in addition (+) at ./odoherty_last.pl line 43.
Use of uninitialized value $2 in addition (+) at ./odoherty_last.pl line 44.
Here is a summary of the time spent on the system for dodoherty:

dodoherty
8
8:6

代码(错误来自的代码段,也是唯一一次使用$ 1和$ 2.)

foreach my $line2 (@user)
{
        $line2 =~ /\S*\((\d{2,2})\:(\d{2,2})\)\s*/;
        $hours = $hours + $1;
        $mins = $mins + $2;

        if( $mins >= 60 )
        {
                $hours = $hours + 1;
                $mins = $mins - 60;
        }
}

4 个答案:

答案 0 :(得分:10)

我认为问题可能出在以下几行。

1. dodohert pts/1 pc-618-012.omhq. Wed Feb 8 09:19 still logged in

那是因为没有任何东西与模式相匹配所以$ 1和$ 2是未定义的。

答案 1 :(得分:4)

正如其他答案中所述,您的正则表达式不匹配,因此$1$2未定义。在使用这些变量之前,必须始终检查以确保相应的正则表达式匹配。

下面我用一些正确的perl代码升级了你的脚本。在这种情况下,+=%=是方便的运营商。您可以在perlop

中了解相关信息

你的正则表达式使用\S*\s*,这两个都是完全没必要的,因为你的正则表达式没有锚定到其他任何东西。换句话说,\S*foo\s*将匹配包含foo的任何字符串,因为它可以匹配foo周围的空字符串。另外,{2,2}表示“匹配至少2次,最多2次”,实际上与{2}“匹配2次”相同。

你会看到我改变了你的数学,那是因为它假定$mins永远不会高于120.我认为从技术上讲,这是一个安全的假设,但是如下所示,它可以处理所有分钟值并成功将其转换为几小时。

以下脚本用于演示。如果您删除DATA并离开<>,则可以按原样使用此脚本:

last user | perl script.pl

<强>代码:

use strict;
use warnings;
use v5.10;  # required for say()

my ($hours, $mins);

while (<DATA>) {   # replace with while (<>) for live usage
    if (/\((\d{2})\:(\d{2})\)/) {
        $hours += $1;
        $mins  += $2;
        if( $mins >= 60 ) {
            $hours += int ($mins / 60);  # take integer part of division
            $mins  %= 60;                # remove excess minutes
        }
    }
}

say "Hours: $hours";
say "Mins : $mins";

__DATA__
1. dodohert pts/1        pc-618-012.omhq. Wed Feb  8 09:19   still logged in
2. dodohert pts/6        ip98-168-203-118 Tue Feb  7 19:19 - 20:50  (01:31)
3. dodohert pts/3        137.48.207.178   Tue Feb  7 14:00 - 15:06  (01:05)
4. dodohert pts/1        137.48.219.250   Tue Feb  7 12:32 - 12:36  (00:04)
5. dodohert pts/21       137.48.207.237   Tue Feb  7 12:07 - 12:23  (00:16)
6. dodohert pts/11       ip98-168-203-118 Mon Feb  6 20:50 - 23:29  (02:39)
7. dodohert pts/9        ip98-168-203-118 Mon Feb  6 20:31 - 22:57  (02:26)
8. dodohert pts/5        pc-618-012.omhq. Fri Feb  3 10:24 - 10:30  (00:05)

答案 2 :(得分:3)

#!/usr/bin/perl

use strict;
my $hours = 0;
my $mins  = 0;
my $loggedIn = 0;
while (<STDIN>)
{
        chomp;
        if (/\S*\((\d{2,2})\:(\d{2,2})\)\s*/)
        {
            $hours = $hours + $1;
            $mins  = $mins + $2;
            if($mins >= 60 )
            {
                $hours = $hours + 1;
                $mins = $mins - 60;
            }
        }
        elsif (/still logged in$/)
        {
            $loggedIn = 1;
        }
}

print "Summary: $hours:$mins ", ($loggedIn) ? " (Currently logged in)" : "", "\n";

答案 3 :(得分:1)

当RE无法匹配时,$ 1和$ 2没有值。

出于这个原因,在一个测试RE成功的条件中使用$ 1,$ 2等被认为是最好的做法。

所以不要这样做:

$string =~ m/(somepattern)/sx;
my $var = $1;

但是要做一些像:

my $var = 'some_default_value';
if($string =~ m/(somepattern)/sx){
  $var = $1;
}