【问题标题】:Perl: Empty/broken AoHPerl:空/损坏的 AoH
【发布时间】:2015-11-14 00:18:22
【问题描述】:

我的模块中有子例程,它使用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 从来没有抱怨过,现在疯了,由于某种原因它拒绝工作。

【问题讨论】:

  • 如果您在返回前使用Data::Dumperprint Dumper \@pwdsettings;,您会得到什么?我的钱会花在grep 过滤太多。
  • Dumper 返回$VAR1 = [];,@pwdsettings 始终为空。
  • 好的。所以这意味着上游问题 - 您的/etc/shadow 对运行脚本的用户是否可读? (你为什么cating它,然后还是打开hte tmp文件?)
  • 其他可能性是 - 正则表达式不匹配。您可以尝试打印$array%hash(同样,通过Dumper)。
  • 是的,脚本正在从 sudo 运行。我更改它只是为了查看模块是否会从影子文件创建 .txt 文件,看看它是否是权限问题。

标签: arrays regex perl hash


【解决方案1】:

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

例如:

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

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

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

$1 包含一堆东西,我怀疑你实际上想要的是用户名 - 但因为 \S+ 是贪婪的,你可能会意外地得到加密的密码。

这将是$fields[0]

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

【讨论】:

  • 这是一个漂亮而优雅的解决方案,谢谢,问题解决了!
【解决方案2】:

我认为您的正则表达式模式是主要问题。不要忘记\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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-10
    • 1970-01-01
    • 2020-01-15
    • 1970-01-01
    • 1970-01-01
    • 2016-04-18
    • 1970-01-01
    相关资源
    最近更新 更多