Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

match users in /etc/shadow file 1

Status
Not open for further replies.

nix45

MIS
Nov 21, 2002
478
US
I have a file called simply "users" with a list of usernames like this...

jdoe
cpurcell
ltorvalds

I want to compare this file to my /etc/shadow file and pull the entries out of the shadow file that match. For example, if my shadow file looked like this...

hjablome:$1$89ekDhxk$MMKcoULbeURwAV4owiqB/:12585:0:99999:7:::
jdoe:$1$jn53vLCl$P/ZtXVPEWvIb518O3vr.:12585:0:99999:7:::
cpurcell:$1$gggLxru$XATg1YNJGi2IuiYCZSaZe.:12587:0:99999:7:::
nobody:$1$.AsmP4tL$Ebg1zADlMyv/w7TlhCqO0:12591:0:99999:7:::
ltorvalds:!!:12600:0:99999:7:::

...the script would return only the matches...

jdoe:$1$jn53vLCl$P/ZtXVPEWvIb518O3vr.:12585:0:99999:7:::
cpurcell:$1$gggLxru$XATg1YNJGi2IuiYCZSaZe.:12587:0:99999:7:::
ltorvalds:!!:12600:0:99999:7:::

I've tried getting this to work with all different kinds of foreach loops and grep statements but I can't get it, I'm still a Perl newbie. Anyone have any ideas on this?

Thanks,
Chris
 
Here's a simplified version of my script. What's wrong with this?
#!/usr/bin/perl -w

@shadow = qw/
hjablome:$1$89ekDhxk$MMKcoULbeURwAV4owiqB:12585:0:99999:7:::
jdoe:$1$jn53vLCl$PZtXVPEWvIb518O3vr.:12585:0:99999:7:::
cpurcell:$1$gggLxru$XATg1YNJGi2IuiYCZSaZe.:12587:0:99999:7:::
nobody:$1$.AsmP4tL$Ebg1zADlMyvw7TlhCqO0:12591:0:99999:7:::
ltorvalds:!!:12600:0:99999:7:::
/;

$jdoe = 'jdoe';

foreach (@shadow) {
if ($jdoe =~ /$_/) { print "$jdoe matches $_\n"; }
}
Chris
 
btw, here's my original broken script, it only prints blank space...
Code:
#!/usr/bin/perl -w

open(PW, "users");
while (<PW>) {
  chomp;
  push @users, $_;
}
close PW;

open(SH, "shadow");
while (<SH>) {
  chomp;
  push @shadow, $_;
}
@shadow = <SH>;
close SH;

foreach $user (@users) {
  @matches = grep(/$user/, @shadow);
}

print "@matches\n";
 
Problems I see:
Code:
open(SH, "shadow");
while (<SH>) {
  chomp;
  push @shadow, $_;
}
@shadow = <SH>;
close SH;
1. You're creating the array @shadow twice, once in the while loop by pushing each element read from <SH>, and then again immediately afterward by assignment. You need one or the other, not both. Either get rid of the assignment @shadow = <SH>; or get rid of the while loop.
Code:
foreach $user (@users) {
  @matches = grep(/$user/, @shadow);
}
2. This is the main problem. You're recreating @matches each time through the loop, resetting it to the result of the grep. @matches will contain at most a single user, or nothing if the last grep fails. You need to push the result into @matches, like so:
Code:
foreach $user (@users) {
    push(@matches, grep(/^$user/, @shadow));
}
You will save grep some work by using ^ at the beginning of the search pattern, since user name occurs at the beginning of each element in @shadow.

HTH
 
Mike,

as I see it you're right, but the way I see it ...
the while loop is filling the array with each successive read, BUT the assignment is overwriting the array with the filehandle at the end of the file i.e. nada

Chris,
get rid of @array=<FH>;

HTH
--Paul

It's important in life to always strike a happy medium, so if you see someone with a crystal ball, and a smile on their face ...
 
with users as parameter:
Code:
@users= <>;
map {chomp } @users; 
open(SH, "/etc/shadow");
while (<SH>) {
        foreach $user (@users) {
                print if /^$user:/;
        }
}
 
mikevh,
1. You're creating the array @shadow twice, once in the while loop by pushing each element read from <SH>, and then again immediately afterward by assignment. You need one or the other, not both. Either get rid of the assignment @shadow = <SH>; or get rid of the while loop.
Sorry, that was a typo. The "@shadow = <SH>;" line wasn't actually there.
2. This is the main problem. You're recreating @matches each time through the loop, resetting it to the result of the grep. @matches will contain at most a single user, or nothing if the last grep fails. You need to push the result into @matches, like so:
Your right, I knew it was something like that but couldn't get it right. Let me give your suggestion a try and reply back with the results.

 
Paul,

You're right about @shadow = <SH> after the while loop returning nada. I wasn't sure about that; I thought after the while returned EOF once, the next read might reset to BOF; but I tried it and it is as you say.

My suggestion to either get rid of the while loop or get rid of @shadow = <SH> would have handled that, though.

It's now moot as nix45 says @shadow = <SH> wasn't really there. But thanks, I learned something.
(But will I remember it next time I need it? [3eyes])

nix45, thanks for the star. :)
 
my /etc/shadow includes:

rpc:.....
rpcuser:....
mail:....
mailnull:....


/^$user/ will alias on users rpc or mail
must use:

/^$user:/
 
Mike,

no worries,

--Paul

It's important in life to always strike a happy medium, so if you see someone with a crystal ball, and a smile on their face ...
 
arn0ld, I don't u/s your last post. Can you explain please?
 
this is basic regular expression (RE). If your users file contains:

ltorvalds

and /etc/shadow contains

ltorvalds: ...
ltorvaldslinux: ....
ltorvaldspenguin: ......

then, the RE:
/^ltorvalds/ # returns all 3
/^ltorvalds:/ #returns the single entry you want
 
[aside]
the colon is the important byte ... as always, as we grow older

--Paul

It's important in life to always strike a happy medium, so if you see someone with a crystal ball, and a smile on their face ...
 
O.K. - why doesn't this work (properly) ?

users.txt
jdoe
cpurcell
ltorvalds

shadow.txt
hjablome:$1$89ekDhxk$MMKcoULbeURwAV4owiqB/:12585:0:99999:7:::
jdoe:$1$jn53vLCl$P/ZtXVPEWvIb518O3vr.:12585:0:99999:7:::
cpurcell:$1$gggLxru$XATg1YNJGi2IuiYCZSaZe.:12587:0:99999:7:::
nobody:$1$.AsmP4tL$Ebg1zADlMyv/w7TlhCqO0:12591:0:99999:7:::
ltorvalds:!!:12600:0:99999:7:::

[red][tt]join -t: users.txt shadow.txt[/tt][/red]

it only outputs:-

[tt]jdoe:$1$jn53vLCl$P/ZtXVPEWvIb518O3vr.:12585:0:99999:7:::
cpurcell:$1$gggLxru$XATg1YNJGi2IuiYCZSaZe.:12587:0:99999:7:::[/tt]

... ltorvalds is missing - and I don't understand why?


Kind Regards
Duncan
 
works with my code, above.

at this point, you should post the contents of the script you are using.
 
Hi Paul

Yes - it is UNIX - files needed sorting first to enable join to work correctly


Kind Regards
Duncan
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top