http://www.perlmonks.org?node_id=92997

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

My first question is can you have split return just the second match instead of one and two. To get that result Ive been doing it like this:
($foo, $match_I_want) = split /:/, $_, [2];

My second and last question is why the following did not work:
($user, $foo{$user}) = split /:/, $_, [2];

I did get it to work by doing this:
($user) = split /:/, $_, [1]; ($temp, $foo{$user}) = split /:/, $_, [2];

Thanks in advance,
blax

Replies are listed 'Best First'.
Re: Questions about split (indexing /etc/passwd)
by petdance (Parson) on Jul 01, 2001 at 11:22 UTC
    First off, that [2] is creating an anonymous array. Get rid of the brackets.

    As to throwing away values, if you want to ignore the first one, just do this: If you're going to ignore the first value, do this:

    (undef, $match_I_want) = split /:/, $_, 2;
    As to your next part:
    I did get it to work by doing this:
    ($user) = split /:/, $_, [1]; ($temp, $foo{$user}) = split /:/, $_, [2];
    Sounds like what you really want is this:
    ($user,$name) = split /:/, $_, 2; $name_lookup{$user} = $name;
    Finally, what you're doing may be unnecessary. I'm assuming that you're doing a build of /etc/passwd, right? You may also want to look into the getpwnam, getpwuid and related functions and let them take care of the work for you. If you want to read everything from the password file, take a look at getpwent.

    xoxo,
    Andy
    --
    <megaphone> Throw down the gun and tiara and come out of the float! </megaphone>

      Thank you both for your replies... they where both very helpfull to me.

      The getpwent function does exactly what I was trying to do. I was wondering if the perl functions are built into the parser or are they installed as scripts? I found a few scripts such as bigint.pl, but they all say "This librarisy is no longer being maintained...".

      Thanks,
      blax
Re: Questions about split
by damian1301 (Curate) on Jul 01, 2001 at 11:04 UTC
    I may be wrong, but I don't think you are supposed to have those brackets around your offset. Another way to do what you want is simply to do something like...
    my($user, $var) = split /:/, $_, 2; $foo{$user} = $var;


    Or maybe I've misunderstood something

    $_.=($=+(6<<1));print(chr(my$a=$_));$^H=$_+$_;$_=$^H; print chr($_-39); # Easy but its ok.
Re: Questions about split
by lestrrat (Deacon) on Jul 01, 2001 at 12:12 UTC

    I think what you are asking for the first question is this:

    ( $match_u_want ) = ( split( /:/, $_ ) )[ 2 ]; # note: gets the third element

    Otherwise, yeah, like everybody else says, you got your third argument confused. You definitely should read more about split :-)

Re: Questions about split
by chromatic (Archbishop) on Jul 01, 2001 at 23:34 UTC
    lestrrat hits the nail on the head (and several posters came very close), but it bears expanding.

    As others have said, your split command is ambiguous. It can take zero to three arguments. How many are you passing? What you really want is a list slice.

    Because split creates a list, and because Perl makes a big deal out of context, you can apply list operations to the result of a split -- as you rightly expected. The trick is to disambiguate what you want.

    A list slice is like an array slice, where you specify only the precise elements you want from the list. For example:

    my @numbers = (1, 2, 3, 4, 5); # want the first and third elements # first element is at position 0 my ($first, $third) = @numbers[0, 2];
    So you were on the right track. You only missed one little thing that occasionally trips me up -- telling Perl to treat the results of split as a list: $item = (split(/:/, $_))[1];

    Again, don't forget that the first element has an index of 0.

Re: Questions about split
by MZSanford (Curate) on Jul 01, 2001 at 12:20 UTC
    It appears ways to do this are numerous and listed, but i believe there is one thing being overlooked in your original attempt. The code :
    ($user, $foo{$user}) = split /:/, $_, [2];
    The problem here is that split() returns and array onto the stack, so i don't believe that you can get $user and use $user in the same array assignment. While there is more than one way to do it, I would look at the above for working code. As for the idea of this specific "syntactic sugar", i don't think i quite works.
    may the foo be with you
Re: Questions about split
by RhetTbull (Curate) on Jul 01, 2001 at 23:26 UTC
    To answer your first question, you could just do this: $field_i_want = (split /:/)[2]; That just creates a single element slice of the list returned by split. If you only wanted elements 2 and 5 you could do this: ($want1,$want2) = (split /:/)[2,5];
Re: Questions about split
by John M. Dlugosz (Monsignor) on Jul 02, 2001 at 03:53 UTC
    Another issue is the evaluation order. I think Perl looks up the lvalue for $foo{$user} before assigning the new value to $user, perhaps even before performing the split! In general, you can't count on order of evaluation so should never use a value more than once in an expression if one of the uses modifies the value.

    —John