Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

traverse through passwd file, and split fields to extract UID/GID

by intoperl (Acolyte)
on Apr 23, 2014 at 10:59 UTC ( [id://1083326]=perlquestion: print w/replies, xml ) Need Help??

intoperl has asked for the wisdom of the Perl Monks concerning the following question:

<> Hello, i have a code below which intends to populate an array using File Handle, and File handle contains the linux passwd file info separated by ":". I am able to succeed till this point. Now, i further need to split each passwd line and extract UID and GID for each user. i am able to achieve this only for the first line of passwd file, and not for rest others. Below is the code and the passwd file i am using, please guide, where am i wrong.

$HAN = "handle"; $FILE = "passwd.txt"; open("$HAN", "$FILE")||die "Error opening file: $!\n"; while(<$HAN>) { @arr = <$HAN>; } foreach(@arr) { @IDINFO = split(/:/,"$arr[$_]"); print "UID is: @IDINFO[2] \n"; print "GID is: @IDINFO[3] \n"; }
Passwd File, i am using: xerox:x:10532:151:simmy xrsa:x:222:507:SystemExpert hintest:x:32381:1873:xThin xtactid:x:65446:266:eVenues ricpay:x:30197:1168:Emeral way:x:10010:111:Expressway t061gs:x:80061:3415:Gurav e456988:x:38975:3477:center zrmda01:x:137001:137:Domino lmda02:x:137002:137:Domino TYMFTP:x:51331:2130:Customer ddda03:x:137003:137:Domino ddda04:x:137004:137:Domino dda05:x:137005:137:Domino dda06:x:137006:137:Domino ddm01:x:88085:137:Notes
output: (its only taking first line and printing multiple times) UID is: 222 GID is: 507 UID is: 222 GID is: 507 UID is: 222 GID is: 507 UID is: 222 GID is: 507 UID is: 222 GID is: 507 UID is: 222 GID is: 507 UID is: 222 GID is: 507 UID is: 222 GID is: 507 UID is: 222 GID is: 507 UID is: 222 GID is: 507 UID is: 222 GID is: 507 UID is: 222 GID is: 507 UID is: 222 GID is: 507 UID is: 222 GID is: 507 UID is: 222 GID is: 507

Replies are listed 'Best First'.
Re: traverse through passwd file, and split fields to extract UID/GID
by Corion (Patriarch) on Apr 23, 2014 at 11:21 UTC

    The central error that leads to the behaviour of your code are the following two lines:

    ... foreach(@arr) { @IDINFO = split(/:/,"$arr[$_]"); ...

    You should see lots of warnings by Perl, because $arr[$_] will always be $arr[0], because $_ is not what you might think it is.

    As a first approach to finding such errors yourself, I would suggest printing $_ and $arr[ $_ ] to make sure that what you see is what you think there should be.

    As a first fix, use $_ instead of $arr[ $_ ].

    In general, there are many things that you can improve in your program to make it more resilient and not rely on features that were superseded by features introduced in Perl 5:

    $HAN = "handle"; $FILE = "passwd.txt"; open("$HAN", "$FILE")||die "Error opening file: $!\n";

    Please do not use global filehandles. Whatever textbook promotes such use, it is hopefully very old, as this is a technique used in Perl 4. Using this technique relies on the idea that nobody nowhere in your program will ever use a filehandle with a similar name. The Perl5 way is to simply use lexical filehandles:

    open my $HAN, $FILE or die "Error opening file '$FILE': $!";

    Now, your file iteration logic is also problematic because it mixes two approaches:

    while(<$HAN>) { @arr = <$HAN>; }

    The while(<$HAN>) { reads one line from $HAN and stores it in $_.

    The @arr= <$HAN> reads all remaining lines from $HAN and stores them in @arr.

    You should use either one of the two idioms but not mix them.

    ... print "UID is: @IDINFO[2] \n"; print "GID is: @IDINFO[3] \n"; ...

    The common way to write these is to use $ instead of @:

    print "UID is: $IDINFO[2] \n"; print "GID is: $IDINFO[3] \n";

      Thanks Corion for handpicking my problems. i learnt a lot.

Re: traverse through passwd file, and split fields to extract UID/GID
by kcott (Archbishop) on Apr 23, 2014 at 12:06 UTC

    G'day intoperl,

    Welcome to the monastery.

    There's builtin functions to do this. No need to reinvent this particular wheel. Try this from your command line:

    $ perldoc -f getpwent

    -- Ken

      Thanks Ken, for bringing up getpwent. BTW, i used the other approach which did not mention getpwent, but still the job was done, by the code below :
      my $HAN = "handle"; my $FILE = "passwd.txt"; open("$HAN", "$FILE")||die "Error opening file: $!\n"; while(<$HAN>) { my ($name,$passwd,$uid,$gid,$gcos,$dir,$shell) = split(/:/,$_); print "UID is: $uid\n"; print "GID is: $gid\n"; } close("$HAN");
        "Thanks Ken, for bringing up getpwent. BTW, i used the other approach which did not mention getpwent, but still the job was done, ..."

        You're welcome. I'm glad you found a working solution.

        For future reference, all of that code could have been replaced by:

        while (my @pw = getpwent) { printf "UID is: %s\nGID is: %s\n", @pw[2,3] }

        By the way, take a look at open for better ways of doing: open("$HAN", "$FILE")

        -- Ken

Re: traverse through passwd file, and split fields to extract UID/GID
by choroba (Cardinal) on Apr 23, 2014 at 12:17 UTC
    Also note that it's not using the first line, but the second one. That's because you read the first one into $_ in the while loop condition, and the rest to @arr in the while loop body (so the loop only iterated once). Usually, you don't use several <...> operators on the same file handle.
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
      Thank you sir, i made a note of it. :)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1083326]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others sharing their wisdom with the Monastery: (2)
As of 2024-04-26 03:31 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found