I got stuck with logic behind loops (while & foreach) and AoH. I have basic knowledge about loops and arrays of hashes, but I can't quite understand how to combine them into 1 single and simple solution. My task is to check regular user's password age, if it is older than n-days (last part is OK for me, I know how to solve it, using GetOptions etc,.).
To accomplish that I figured out a solution:
1 Load file /etc/passwd into script, preform regex search to find out regular users. Regular users in Linux like systems have IDs from 1000 and above, so I use this regex to find out those:
/(\w+)[:]x[:]1[0-9]{3}/
2 Load results of regex serch in to array:
my (@Usernames, %pwdsettings);
while (my $pwdsettings = <$fh2>) {
if ($pwdsettings =~ /(\w+)[:]x[:]1[0-9]{3}/) {
$pwdsettings{"Username"} = $1;
push (@Usernames, \%pwdsettings);
}
}
3 Preform chage check for every entry in array:
my $pwdsett_dump = "tmp/pwdsett-dump.txt";
...
foreach (@Usernames) {
system("chage -l $_ > $pwdsett_dump")
}
4 Open $pwdsett_dump
and then preform second regex search to get date of last password change. After, load results into existing hash inside array (AoH):
open (my $fh3, "<", $pwdsett_dump) or die "Could not open file '$pwdsett_dump': $!";
while (my $array = <$fh3>) {
if ($array =~ /^Last\s+password\s+change\s+:\s(\w{3})\s+(\d{2}),\s+(\d{4})/) {
$pwdsettings{"Month"} = $1;
$pwdsettings{"Day"} = $2;
$pwdsettings{"Year"} = $3;
}
}
But, somewhere it went terribly wrong. My script loads only 1 user in to AoH, second user is never loaded and I get $VAR1->[0]
.
What I want is to understand how AoH and loops are created in right way.
Full script:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my $pwdsett_dump = "tmp/pwdsett-dump.txt";
my $usernames_dump = "tmp/usernames-dump.txt";
system("cat /etc/passwd > $usernames_dump");
open (my $fh2, "<", $usernames_dump) or die "Could not open file '$usernames_dump': $!";
my (@Usernames, %pwdsettings);
while (my $pwdsettings = <$fh2>) {
if ($pwdsettings =~ /(\w+)[:]x[:]1[0-9]{3}/) {
$pwdsettings{"Username"} = $1;
push (@Usernames, \%pwdsettings);
}
}
foreach (@Usernames) {
system("chage -l $_ > $pwdsett_dump")
}
open (my $fh3, "<", $pwdsett_dump) or die "Could not open file '$pwdsett_dump': $!";
while (my $array = <$fh3>) {
if ($array =~ /^Last\s+password\s+change\s+:\s(\w{3})\s+(\d{2}),\s+(\d{4})/) {
$pwdsettings{"Month"} = $1;
$pwdsettings{"Day"} = $2;
$pwdsettings{"Year"} = $3;
}
}
print Dumper \@Usernames;
you need to append the file when you output meaning use ">>" instead of ">" which will overwrite the file.
system("chage -l $_ >> $pwdsett_dump")
as you are running it in loop you are overwriting each time the loop executes.
Use:
foreach (@Usernames) {
system("chage -l $_ >> $pwdsett_dump")
}
########sample script
#!/usr/bin/perl
use strict;
use warnings;
my $usernames_dump = "/etc/passwd";
open (my $fh2, "<", $usernames_dump) or die "Could not open file '$usernames_dump': $!";
my @pwdsettings;
my $i =0;
my @pwdsett_dump;
while (<$fh2>) {
if ($_ =~ /(\w+)[:]x[:]1[0-9]{3}/) {
my @user = split(/:/, $_);
$pwdsettings[$i] = $user[0];
$pwdsett_dump[$i] = `chage -l $user[0]|grep Last`;
$pwdsett_dump[$i] =~ s/Last.*://;
$pwdsett_dump[$i] =~ s/,//;
my @m = split(/ /,$pwdsett_dump[$i]);
print "$user[0]\t Date: $m[2] Month: $m[1] Year: $m[3]\n";
$i++;
}
}
Output: testuser Date: 12 Month: May Year: 2015