I want to scan the passwd file and print only lines if the user is not locked. That is, passwd -S $user
does not return "Password: locked." I can do easily in ksh. What is the best way to do this in Perl?
views:
164answers:
4Previously, this answer reported how to print only locked users. Mistake corrected.
On Linux, a locked user account has a password which begins whith '!'
. You can parse the colon-separated /etc/shadow
file yourself with:
# Run as root with /etc/shadow as program argument
while (<>) {
chomp;
my ($user, $password, $remainder) = split /:/, $_, 3;
print $user."\n" unless $password =~ /^!/;
}
Edit: Another, portable, way is to use the getpwent function:
# Must run as root
while (my ($user, $password) = getpwent) {
print $user."\n" unless $password =~ /^!/;
}
Note: You need to be root to read users' passwords from /etc/shadow
and to find out whether a user is locked or not.
I'm not sure if you're looking for a command-line way to do it or not, and the following code assumes that the output of passwd -S is exactly how you specified it (which probably won't work in practice), but this is one approach:
cat /etc/passwd | perl -ne '$user = (split /:/)[0]; print "$user\n" if `passwd -S $user` ne "Password: locked"'
In practice, you'd probably need some kind of hairy regex at the end, like:
`passwd -S $user` !~ /^\s*Password\s*:\s*locked\s*$/im'
Where the 'i' at the end makes it case insensitive (which probably isn't necessary), and the 'm' allows matching multiple lines of output [from passwd -S]. It's hard to say exactly what you'd need without seeing the exact output you're matching (on your *nix).
For example, on cygwin, I think the equivalent would be this:
`passwd -S $user` !~ /^\s*Account\s+disabled\s+:\s+yes\s*$/im'
The same as one-liner.
sudo perl -F: -lane 'print $F[0] if $F[1]!~/^!/' /etc/shadow
open(F,"<","/etc/shadow") or die "Cannot open shadow file:$!\n";
while(<F>){
chomp;
@s = split /:/;
if ( $s[1] !~ /!/){
print "user: $s[0] not locked \n";
}
}
close(F);
use as root.