简体   繁体   中英

Perl merging two text files with common column

Very new to Perl and this is giving me a headache. I have a text file with user specific information like addresses, email, dates. I want to compare this file to the /etc/passwd file and if the username exists in the passwd file ,merge the etc/passwd data in an array to then manipulate further. The user names as alpha-numerical like "abc123"

this is what I have done so far:

    open PASSWD, "</etc/passwd" or die "$!"; # /etc/passwd file is opened to be searched for a matching username
    open INFO, "<gtc_members.txt" or die "$!"; #information.txt is opened to search for matching user name


             while (<PASSWD>) {
                    chomp;

                    my $userName = (split ":", $_)[0];
                    $homeDirectory = (split ":", $_)[5];
                    $fullName = (split ":", $_)[4];
                    $shell = (split ":", $_)[6];

                    push @userNames, ($fullName, $homeDirectory,$shell); # if $userName eq $searchName;
                    }

            while (<INFO>) {
                    chomp;
                    my $userName1 = (split ",", $_)[2];
                    $userAddress = (split ",", $_)[3];
                    $userEmail = (split ",", $_)[4];
                    $userManager = (split ",", $_)[6];

    push @userNames_1, ($userAddress,$userEmail,$userManager);# if $userName1 eq $searchName;
                    }

And this is where I get stuck. Despite many attempts with different code I cannot merge the two arrays @userNames and @userNames1 on a common user name. It has got so ridiculous now that none of this makes sense. I have tried using a hash but struggling to match the common user name as in this example.

First of all, never ever parse /etc/passwd directly. Use getpw* functions instead. The second, there is not clear what you are trying to do with data you will get but you can take idea from this:

perl -F, -plae'if(my($fullName, $Dir, $Shell) = (getpwnam($F[2]))[6,7,8]) {$_ .= ",$fullName,$Dir,$Shell"}' gtc_members.txt

All /etc/passwd entries can be obtained by

perl -E'$,=":";say @a while @a = getpwent()'

Indeed better to use getpw* functions to fetch system user data, but if you insist reading /etc/passwd then use following strategy:

  1. read /etc/passwd into hash, store anonymous array of interesting passwd file data inside that hash, so no @userNames array is needed anymore.
  2. parse the INFO file, push interesting fields, then lookup by $userName in hash and if exists - push the array from hash which stores /etc/passwd data.

This example does not invent anything new, but let me put it anyway. Notes: final array @userNames_1 is reset on evey iteration of second loop. Assume you do something with it inside second loop. Putting all into large array is much useless IMHO. But if needed, please remove my right after push and it won't be reset. $userName is lexically local to the while loop blocks, so same name is used. Also I am fetching anonymous array as a reference, as dereferencing it as @{$hash{$index}} gives me "Uninitialized value" error. Not sure if it's very correct, but it works anyway.

open PASSWD, "</etc/passwd" or die "$!";
open INFO, "<gtc_members.txt" or die "$!";

my %pwhash;

while (<PASSWD>) {
    chomp;
    my ($userName, $fullName, $homeDirectory, $shell) = (split /:/)[0, 4, 5, 6];
    $pwhash{$userName} = [$fullName, $homeDirectory, $shell];
}

while (<INFO>) {
    chomp;
    my ($userName, $userAddress, $userEmail, $userManager) = (split /,/)[2, 3, 4, 6];
    push my @userNames_1, ($userAddress, $userEmail, $userManager);
    push @userNames_1, (@$pwinfo) if ($pwinfo = $pwhash{$userName});
    # test printout
    print join(',', @userNames_1), "\n";
}

Try this out:

  use Data::Dumper;
  use strict;
  use warnings;
  my %users_in_passwd;
  while (<PASSWD>) {
      chomp;      
      my $userName = (split ":", $_)[0];
      my $homeDirectory = (split ":", $_)[5];
      my $fullName = (split ":", $_)[4];
      my $shell = (split ":", $_)[6];
      $users_in_passwd{$userName} = [$fullName, $homeDirectory,$shell];
  }
   while (<INFO>) {
   chomp;
       my $userName1 = (split ",", $_)[2];
       my $userAddress = (split ",", $_)[3];
       my $userEmail = (split ",", $_)[4];
       my $userManager = (split ",", $_)[6];
       if (exists  $users_in_passwd{$userName}){
          my @data_in_passwd = @{$users_in_passwd{$userName}};
          print Dumper($userName,$userName1,\@data_in_passwd,);
          ### do something
       }
   }  

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM