Perl regex help

Hello,
What I am attempting is pulling the username and first/last name from the etc/passwd file

username:x:1333:1333:fnamel name,,,:/home/smele:/bin/bash
username:x:1334:1334:fname lname,,,:/home/tjmullins:/bin/bash

The code below is pulling mutiple duplicate entries and throws an error:

Use of uninitialized value $x in concatenation (.) or string at ./part2c line
        27 (#1)

Outside the loop it only prints the last item on the array.

Any help would be appreciated.
open (IN,"/etc/passwd");
my @wholeFile = <IN>;
close IN;

 
my @uname = grep /^\w.*?/, @wholeFile;
#convert array into string
my $string = join('',@uname);

my @data = split (/\n/, $string);
 
 #filter out username
foreach my $line(@data) {
my @id = ($line  =~ /\s*(\S+)\:\w\:\d+\:\d+\:(\S+\s+\S+)\S+\S+\S+\:\/\S+\/\S+\:\/\S+\/\S+\s*$/mg);
my $z = $1;
#print "$z\n";
my $x = $2;
print "$x\n";
 
}

Open in new window

fac66Asked:
Who is Participating?
 
Terry WoodsIT GuruCommented:
For example, I think in cases like:
username:x:1334:1334::/home/tjmullins:/bin/bash

Your get_last_name sub is likely to return an undefined value from $1, because:
/(\S+\s\S+\s*\S*)/g;
doesn't match.
0
 
Terry WoodsIT GuruCommented:
Try swapping:

print "$x\n";

With:

  if (defined $x) { print "$x\n" };
0
 
fac66Author Commented:
Thanks for the reponse.

This is in a sub function
The return is only returning the last item in the array.
How do I return all users?
sub get_user_id {
 
my @uname = grep /^\w.*?/, @wholeFile;
#convert array into string
my $string = join('',@uname);
#print $string;

#splits at line breaks
my @data = split (/\n/, $string);
my $z;
foreach my $line(@data) {
 my @id = ($line  =~ /\s*(\S+)\:\w\:\d+\:\d+\:(\S*\s*\S*\s*\S*)\S+\S+\S+\:\/\S+\/\S+\:\/\S+\/\S+\s*$/mg);
 $userid;= $1;
 #if (defined $userid ) { print "$userid\n" };

 }

return $userid;
 }

Open in new window

0
Cloud Class® Course: Microsoft Office 2010

This course will introduce you to the interfaces and features of Microsoft Office 2010 Word, Excel, PowerPoint, Outlook, and Access. You will learn about the features that are shared between all products in the Office suite, as well as the new features that are product specific.

 
Terry WoodsIT GuruCommented:
To return an array of userids, do something like this:
sub get_user_id {
 
my @uname = grep /^\w.*?/, @wholeFile;
#convert array into string
my $string = join('',@uname);
#print $string;

#splits at line breaks
my @data = split (/\n/, $string);
my $z;
my @userids = ();
foreach my $line(@data) {
 my @id = ($line  =~ /\s*(\S+)\:\w\:\d+\:\d+\:(\S*\s*\S*\s*\S*)\S+\S+\S+\:\/\S+\/\S+\:\/\S+\/\S+\s*$/mg);
 $userid;= $1;
 if (defined $userid ) { 
   push(@userids,$userid);
 }

}
return @userids;

}

Open in new window

0
 
fac66Author Commented:
Actually I rewrote it and I think I just about got it.

Although I am getting errors in a subroutine that works when it's ran seperate.
now. I put the numbers next to the lines the errors are in the code.
Anyone got any ideas?

 Use of uninitialized value in transliteration (tr///) at ./final4 line 123 (#1)
    (W uninitialized) An undefined value was used as if it were already
    defined.  It was interpreted as a "" or a 0, but maybe it was a mistake.
    To suppress this warning assign a defined value to your variables.

    To help you figure out what was undefined, perl will try to tell you the
    name of the variable (if any) that was undefined. In some cases it cannot
    do this, so it also tells you what operation you used the undefined value
    in.  Note, however, that perl optimizes your program and the operation
    displayed in the warning may not necessarily appear literally in your
    program.  For example, "that $foo" is usually optimized into "that "
    . $foo, and the warning will refer to the concatenation (.) operator,
    even though there is no . in your program.

Use of uninitialized value $fc in substitution (s///) at ./final4 line 124 (#1)
Use of uninitialized value $fc in concatenation (.) or string at ./final4 line
        127 (#1)
Use of uninitialized value $f in concatenation (.) or string at ./final4 line
        129 (#1)

#!/usr/bin/perl
use diagnostics;
use strict;
use warnings;
#use Data::Dumper;

my $num = 0;

 if (@ARGV != 1)

 {
     print "\nUsage: $0 LastName\n\n";
     exit(1);
 }
 chomp $ARGV[0];


#-------------------


open (IN,"/etc/passwd");
my @wholeFile = <IN>;
close IN;

foreach my $line (@wholeFile)
{
    my $userid = &get_user_id($line);
    my $lastname = &get_last_name($line);
  #  print "$userid has a last name of $lastname!\n";

 if(&soundex($lastname) eq &soundex($ARGV[0]))

     {
         my @args = ("finger", $userid);
         system (@args);
         $num++;
     }
}

print "\nThe name you were looking for, ".$ARGV[0]." converted to ".soundex($ARGV[0])."\n";



 if ($num == 0)

     {

         print "finger: ".$ARGV[0].": no such user.\n\n";

     }

#---------------userid----------------------

sub get_user_id

 {
my @uname = grep /^\w.*?/, @wholeFile;
#convert array into string
my $string = join('',@uname);

my @data1 = split (/\n/, $string);

      @data1 = split(/:/,shift);
    # print "$userid[0]";
     return $data1[0];
 }

#-----------lastname-------------

sub get_last_name
 {
my @uname = grep /^\w.*?/, @wholeFile;
#convert array into string
my $string = join('',@uname);

my @data1 = split (/\n/, $string);

      @data1 = split (/:/,shift);

     if ($data1[4] ne "" || $data1[4] ne " ")
     {
         $data1[4] =~ s/,.*?//g;
         $data1[4] =~ /(\S+\s\S+\s*\S*)/g;
         return $1;
     }
     else
     {
         print "No last name provided\n";
     }
 }

 
 

#--------------soundex subroutine---------------------------------------------
sub soundex
{

  my $temp = uc shift;    # gets the name passed to the function
                           # and uppercases it

$temp =~ s/^[^A-Z]//;   # remove first character if not letter

# Eliminate doubled-letters

my @x = split(//,$temp);
$temp = '';
my $lastx = '';

foreach my $x ( @x)
{
    if ( ( $lastx eq '' ) || ( $x ne $lastx ) )
    {
        $temp .= $x;
        $lastx = $x;
    }
}
#print STDERR "$temp\n";

# Split into first letter and the rest
my ($f, $fc) = ($temp =~ /(\w)(\w+)/);
 
# soundex weighting
123 $fc =~ tr/AEHIOUWYBFPVCGJKQSXZDTLMNR/00000000111122222222334556/;
124 $fc =~  s/0+//g; #gets rid of extra 0's

# first four digits, pad with zeroes on right if needed
127 $fc = substr($fc.'000',0,4);   
 
129 my $sdxValue = $f.$fc;

  return $sdxValue;   
    
}

Open in new window

0
 
Terry WoodsIT GuruCommented:
If your /etc/passwd is like mine, then you won't have a first and last name on every line. I believe some cases are resulting in an uninitialised value, which is being passed along to the code that produces the error. Try tightening up the handling where the expected values aren't found.
0
 
fac66Author Commented:
Not sure what you mean, keep in mind I am pretty new to \Perl.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.