CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Beginner:
just starting out, comparing two arrays

 



scottmusician
New User

Jun 23, 2013, 6:17 AM

Post #1 of 4 (532 views)
just starting out, comparing two arrays Can't Post

Hi all,

This is my first post!

I've just started a perl class, and I'm trying to write a simple script to optimize the /etc/groups file, to make sure that it only contains entries that also exist in /etc/passwd .

here's what I have so far, but it all seems a little cumbersome. Any thoughts would be great!

Thanks,
Scott


Code
#!/usr/local/bin/perl 

open(F, "/etc/passwd");
@passwd = <F>;
chop(@passwd);
open(F, "/etc/group");
@group = <F>;
chop(@group);

for ($i=0; $i<$#group; $i++) {
$line = $group[$i];
$line =~ /^(..*):(..*):(..*):(..*)$/;
($group, undef, undef, $members) = ($1, $2, $3, $4);
@members = split(/,/, $members);
foreach $m (@members) {
printf("%s\n", $m) unless grep(/^$m:/, @passwd);
}
}



(This post was edited by scottmusician on Jun 23, 2013, 6:23 AM)


BillKSmith
Veteran

Jun 23, 2013, 6:53 AM

Post #2 of 4 (528 views)
Re: [scottmusician] just starting out, comparing two arrays [In reply to] Can't Post

First, check the FAQ.

Code
perldoc -q "difference of two arrays"


This is not exactly what you need, but should get you on the right track. Use a hash!
Good Luck,
Bill


Laurent_R
Veteran / Moderator

Jun 23, 2013, 8:53 AM

Post #3 of 4 (525 views)
Re: [scottmusician] just starting out, comparing two arrays [In reply to] Can't Post

In other words: read /etc/passwd and store the user (first field) in a hash (as a key to the hash, with any value you like). Then read /etc/groups, take the user and check if it exists un the hash. And you are done.

No need to load any of the files into an array. You only need to load the users into the hash:



Code
my %user_hash; 
while (<$passwd>) {
my $user = (split /:/)[0]; # could also be a regex: my $user = $1 if /^(\w+):/;
$user_hash{$user} = 1;
}


I leave it to you to do the second part, reading the groups file, retrieving the user (same way as above) and checking if the user exists in the %user_hash hash. It is really another 2 or 3 lines of code.


hwnd
User

Jun 24, 2013, 9:43 PM

Post #4 of 4 (492 views)
Re: [Laurent_R] just starting out, comparing two arrays [In reply to] Can't Post

A few options you can do here, following what the other OPS have said. Storing in a hash.

Example '/etc/passwd'


Code
root:x:0:0:root:/root:/bin/bash  
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin



Example '/etc/group'


Code
root:x:0:root  
bin:x:1:root,bin,daemon
daemon:x:2:root,bin,daemon
adm:x:4:root,adm,daemon



The long way doing this:


Code
use strict;  
use warnings; # always use for catching errors early.

my %users; # define empty hash %users
my %group; # define empty hash %group

open my $fh1, '<', '/etc/passwd' or die "failed open $!";
while (<$fh1>) {
my $id = (split /:/)[0]; # split the fields, [0] is the first field before the colon.
$users{$id} = 1; # build %users hash with $id as key and value as 1
}
close $fh1;

open my $fh2, '<', '/etc/group' or die "failed open $!";
while (<$fh2>) {
my $id = (split /:/)[0]; # split the fields, [0] is the first field before the colon.
$group{$id} = 1; # build %group hash with $id as key and value as 1
}
close $fh2;

for ( keys %group ) { # iterate over %group hash keys
print "$_\n" unless $users{$_}; # print the extra that dont match both hashes
}



An easier way:


Code
Using map here. map runs an expression on each list element and returns list results.   
Were defining hash %users and %group to map the first field of the file with split and
make that field our hash key and give it the value of 1. Then we are using @results array
to use map to check if the %users key exists in %group and finally iterate through @results
and print the users found that were different.

open my $fh1, '<', '/etc/passwd' or die "failed open $!";
open my $fh2, '<', '/etc/group' or die "failed open $!";

my %users = map { (split /:/)[0] => 1 } <$fh1>;
my %group = map { (split /:/)[0] => 1 } <$fh2>;
close $fh1;
close $fh2;

my @results = map { $users{$_} ? () : $_ } keys %group;

foreach (@results) {
print "'$_' found in group\n";
}



(This post was edited by hwnd on Jun 24, 2013, 9:48 PM)

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives