Perl:获取关键值

时间:2015-08-19 14:41:27

标签: perl hash

我正在尝试从模块中的哈希获取键值:

Module.pm

...
my $logins_dump = "tmp/logins-output.txt";
system("cat /var/log/secure | grep -n -e 'Accepted password for' > $logins_dump");
open (my $fh, "<", $logins_dump) or die "Could not open file '$logins_dump': $!";

sub UserLogins {
    my %user_logins;
    while (my $array = <$fh>) {
        if ($array =~ /Accepted\s+password\s+for\s+(\S+)/) {
            $user_logins{$1}++;
         }
    }
    return \%user_logins;
}

sub CheckUserLogins {
    my $LoginCounter;
    my $UsersToCheck = shift @_;
    if (exists %{UserLogins()}{$UsersToCheck}){
        $LoginCounter = %{UserLogins{$UsersToCheck}}; #How many logins?
    }
    else {
        $LoginCounter = "0";
    }
    return \$LoginCounter;
}

Script.pl

$UserLoginCounter = Module::CheckUserLogins($UsersToPass);

我将用户名传递给脚本并检查用户名是否为哈希,如果是,我需要返回登录次数,我正在尝试使用$LoginCounter。由于某种原因,脚本只返回0或undef。

2 个答案:

答案 0 :(得分:2)

嗯,对于初学者 - 你有CheckUserLogins而不是CheckLoginAttempts

假设这只是一个错字 - UserLogins返回一个哈希引用 - 一个标量值。如果0检查失败,您将获得exists

如果确实存在,那么你就是这样做的:

$LoginCounter = %{UserLogins{$UsersToCheck}};

哪个无效。您是否已启用strictwarnings?因为您正在尝试将哈希值分配给标量,这不会达到您想要的效果。

你可能意味着:

$LoginCounter = ${UserLogins()} -> {$UsersToCheck};

UserLogins取消引用该引用,然后查找一个键。

但是,我可能会稍微改变一下你的问题 - 当你做你正在做的事情时它只能工作一次,因为每次你打电话UserLogins它会创建一个新的哈希,但你不要快退$fh

所以我建议:

use strict;
use warnings;

{
    my %userlogins;

    sub inituserlogins {
        open( my $fh, "<", '/var/log/secure' )
            or die "Could not open file: $!";
        while ( my $array = <$fh> ) {
            if ( $array =~ /Accepted\s+password\s+for\s+(\S+)/ ) {
                $userlogins{$1}++;
            }
        }
        close($fh);
    }

    sub CheckUserLogins {
        my ($UsersToCheck) = @_;
        inituserlogins() unless %userlogins;
        return $userlogins{$UsersToCheck} ? $userlogins{$UsersToCheck} : 0;
    }
}

答案 1 :(得分:1)

您不得在词汇标识符中使用大写字母,因为Perl会为包名称等全局标识符保留它们

其中一个主要问题是您正在使用

exists %{UserLogins()}{$UsersToCheck}

应该是

exists UserLogins()->{$UsersToCheck}

exists ${UserLogins()}{$UsersToCheck}

你有use strictuse warnings,你应该有吗?

另一个问题是,每次拨打UserLogins时,您都会阅读整个文件。这意味着第二次和稍后调用CheckUserLogins(调用UserLogins)将找不到任何内容,因为已到达文件末尾

您应该调用您的suibroutine user_logins并将其称为一次,将结果存储为标量变量。该程序显示了如何

use strict;
use warnings;
use v5.14;  # For state variables

sub user_logins {

    open my $fh, '<', '/var/log/secure' or die $!;

    my %user_logins;

    while ( <$fh> ) {
        if ( /Accepted\s+password\s+for\s+(\S+)/ ) {
            ++$user_logins{$1};
        }
    }

    \%user_logins;
}

sub check_user_logins {
    my ($users_to_check) = @_;
    state $user_logins = user_logins();
    $user_logins->{$users_to_check} // 0;
}