Perl:空/破AoH

时间:2015-08-20 11:18:45

标签: arrays regex perl hash

我的模块中有子程序,它使用shadow文件上的正则表达式搜索检查(常规)用户密码年龄:

Module.pm

my $pwdsetts_dump = "tmp/shadow_dump.txt";
system("cat /etc/shadow > $pwdsetts_dump");
open (my $fh1, "<", $pwdsetts_dump) or die "Could not open file '$pwdsetts_dump': $!";

    sub CollectPWDSettings {
        my @pwdsettings;
        while (my $array = <$fh1>) {
            if ($array =~ /^(\S+)[:][$]\S+[:](1[0-9]{4})/) {
                my $pwdchange = "$2";
                if ("$2" eq "0") {
                    $pwdchange = "Next login";
                }
                my %hash = (
                    "Username"  =>  $1,
                    "Last change"   =>  $pwdchange
                );
                push (@pwdsettings, \%hash);
            }
        }
        my $current_date = int(time()/86400); # epoch 
        my $ndate = shift @_;                 # n-days
        my $search_date = int($current_date - $ndate);
        my @sorted = grep{$_->{'Last change'} > $search_date} @pwdsettings;

        return \@sorted;
    }

脚本分为两个步骤:   1.加载所有密码设置   2.搜索超过n天的密码

在我的主脚本中,我使用以下脚本:

my ($user_changed_pwd);
    if (grep{$_->{'Username'} eq $users_to_check} @{Module::CollectPWDSettings("100")}) {
        $user_changed_pwd = "no";
    }
    else {
        $user_changed_pwd = "yes";
    }

第一步出现问题,AoH永远不会被填充。我也很确定这个子程序对我来说总是有效,strictwarnings从不抱怨它,现在坚持,因为某些原因它拒绝工作。

2 个答案:

答案 0 :(得分:2)

我刚刚对我的/etc/shadow运行你的正则表达式而没有匹配。如果我放弃前导1我会得到一些点击。

E.g:

$array =~ /^(\S+)[:][$]\S+[:]([0-9]{4})/

但就个人而言 - 我建议不要尝试使用正则表达式,而是依赖/etc/shadow定义为由:分隔的事实。

my @fields = split ( /:/, $array ); 

$ 1包含很多东西,我怀疑你想要的是用户名 - 但是因为\S+贪婪,你可能会意外地以加密密码结束。

这将是$fields[0]

然后来自man shadow的“最后更改”字段为$fields[2]

答案 1 :(得分:0)

我认为你的正则表达式是主要问题。不要忘记\S匹配包括冒号:在内的任何非空格字符,\S+会尝试尽可能匹配,因此它会愉快地跳过多个字段文件

我认为使用split将每条记录分隔为冒号分隔的字段是一种更好的方法。我也认为,最好将数据存储为将用户名与其密码历史相关联的哈希值,而不是两元素哈希数组@pwdsettings

这是我怎么写的。它会打印密码历史记录大于90天的所有用户名列表

use strict;
use warnings;

use Time::Seconds 'ONE_DAY';

my @shadow = do {
    open my $fh, '<', '/etc/shadow' or die qq{Unable to open "/etc/shadow" for input: $!};
    <$fh>;
};

print "$_\n" for @{ collect_pwd_settings(90) };

sub collect_pwd_settings {

    my ($ndate) = @_;

    my %pwdsettings;

    for ( @shadow ) {
        my ($user, $pwdchange) = (split /:/)[0,2];
        $pwdsettings{$user} = $pwdchange;
    }

    my $current_date = time / ONE_DAY;

    my @filtered = grep { $current_date - $pwdsettings{$_} > $ndate } keys %pwdsettings;

    return \@filtered;
}