The code below returns me nothing.

Discussion in 'Perl Misc' started by Facco Eloelo, Jul 30, 2004.

  1. Facco Eloelo

    Facco Eloelo Guest

    I find NetAddr::IP is good.
    But the code below returns me nothing.
    can some body help me? thx.


    #!/usr/bin/perl
    use NetAddr::IP;

    my $list_file = 'IPlist.txt';
    my $segment_file = 'IPsegment.txt';
    my $match_file = 'match.txt';

    open my $IPsegment, '<', $segment_file or die "Cannot open $in_file: $!";
    open my $IPlist, '<', $list_file or die "Cannot open $in_file: $!";
    open my $IPmatch, '>', $match_file or die "Cannot open $out_file: $!";

    while ( <$IPsegment> ) {
    chomp;
    $segment=$_;
    my $space = NetAddr::IP->new($segment);

    while ( <$IPlist> ) {
    chomp ($_);
    ($domain, $domip) = split(/,/, $_);
    for my $ip (map {NetAddr::IP->new($_) } $domip)
    {
    print my $IPmatch $domain,$ip, "\n"
    if $space->contains($ip);
    }
    }
    }


    --
     
    Facco Eloelo, Jul 30, 2004
    #1
    1. Advertisements

  2. That "map" is incorrectly applied. Map works on lists and $domip is
    a scalar variable, and consequently, map function doesn't do
    anything. If you pushed your IP addresses into an array and applied
    map function to the array, it would work better. Here is what the fine
    manual says:
    map BLOCK LIST
    map EXPR,LIST
    Evaluates the BLOCK or EXPR for each element of LIST (locally
    setting $_ to each element) and returns the list value composed
    of the results of each such evaluation. In scalar context,
    returns the total number of elements so generated. Evaluates
    BLOCK or EXPR in list context, so each element of LIST may pro-
    duce zero, one, or more elements in the returned value.


    Notice the word "LIST", printed in capitals. Scalar is not a list.
     
    Mladen Gogala, Jul 30, 2004
    #2
    1. Advertisements

  3. Facco Eloelo

    Facco Eloelo Guest

    Still have some problem :-(

    #!/usr/bin/perl
    use NetAddr::IP;
    use warnings;

    my $list_file = 'IPlist.txt';
    my $segment_file = 'IPsegment.txt';
    my $match_file = 'match.txt';

    open my $IPsegment, '<', $segment_file or die "Cannot open $segment_file: $!";
    open my $IPlist, '<', $list_file or die "Cannot open $list_file: $!";
    open my $IPmatch, '>', $match_file or die "Cannot open $match_file: $!";

    @line=<$IPsegment>;
    $num = @line;
    for($i=0;$i<$num;$i++)
    {
    my $space = NetAddr::IP->new($line[$i]);

    for my $ip (map { NetAddr::IP->new($_) } <$IPlist>)
    {
    print $ip, "\n"
    if $space->contains($ip);
    }
    }
    --
     
    Facco Eloelo, Jul 30, 2004
    #3
  4. Facco Eloelo

    Uri Guttman Guest

    MG> That "map" is incorrectly applied. Map works on lists and $domip is
    MG> a scalar variable, and consequently, map function doesn't do
    MG> anything. If you pushed your IP addresses into an array and applied
    MG> map function to the array, it would work better. Here is what the fine
    MG> manual says:
    MG> map BLOCK LIST
    MG> map EXPR,LIST

    MG> Notice the word "LIST", printed in capitals. Scalar is not a list.

    that is wrong. a single value is just a list with one element. there is
    no problem with using map (nor any other func that takes a list) on a
    single scalar. ever try push @foo, $bar? works fine and it too takes a
    list as its second argument.

    so the OP's problem lies elsewhere.

    uri
     
    Uri Guttman, Jul 30, 2004
    #4
  5. Facco Eloelo

    Anno Siegel Guest

    It doesn't make much sense, but the map application is valid.
    Not true. When the syntax requires a LIST, any mixture of scalars,
    arrays (and even hashes) can be given. They will all be flattened
    into one list.
    That's not necessary. A special case of the above is

    map NetAddr::IP->new($_), $domip;

    That will execute and return NetAddr::IP->new($domip). "map" is
    unnecessary, but it works.
    Sometimes it is.

    Anno
     
    Anno Siegel, Jul 30, 2004
    #5
  6. Facco Eloelo

    Anno Siegel Guest

    You are trying to read the same file repeatedly in a loop. After the
    first time through, the file will be positioned at eof and stay there.
    You need to rewind the file (see perldoc -f seek).

    A better solution would probably be to read $IPlist once and store
    the contents in a data structure. A hash keyed on $ip looks reasonable.

    [snip]

    Anno
     
    Anno Siegel, Jul 30, 2004
    #6
  7. Facco Eloelo

    Anno Siegel Guest

    It runs? It contains a trivial but fatal error, twice. After correction
    it does work as expected. It also made clearer to me what the purpose
    of the code is.

    So the OP is trying to match the same list of IP's (from some file,
    that part is snipped) against a series of IP spaces (from another file).

    So first read the list of addresses. Assuming each line is ready for
    consumption by NetAddr::IP (which may not be true):

    my @addrs;
    while ( <$addrs> ) {
    chomp;
    push @addrs, NetAddr::IP->new($_);
    }

    Now read each range in sequence and check all addresses against each
    one:

    while ( <$spaces> ) {
    chomp;
    my $space = NetAddr::IP->new( $_);
    for ( @addrs ) {
    if ( $space->contains( $_) ) {
    # report match
    }
    }
    }

    The same method could be applied with the roles of $addrs and $spaces
    reversed: Read all spaces into a list, then apply them to each address
    as it is read. If the list of addresses is huge, but the list of spaces
    isn't, that may be preferable. Both methods report the same matches,
    but in a different sequence.

    Anno
     
    Anno Siegel, Jul 30, 2004
    #7
  8. I stand corrected. It is syntactically corect, but doesn't make
    much sense.
     
    Mladen Gogala, Jul 31, 2004
    #8
  9. Facco Eloelo

    Uri Guttman Guest

    MG> I stand corrected. It is syntactically corect, but doesn't make
    MG> much sense.

    passing a single scalar to map does make sense in some circumstances. i
    use it to alias a scalar to $_ when i have code that must act on
    $_. check out Sort::Maker for a case like that where i generate map code
    on scalar values.

    uri
     
    Uri Guttman, Jul 31, 2004
    #9
  10. Wow! Thanks Uri, you're really a master! I don't consider myself
    a perl guru, as a matter of fact, I'm rather far from it, and I'm
    grateful for anything that I can learn.
     
    Mladen Gogala, Jul 31, 2004
    #10
  11. Facco Eloelo

    Anno Siegel Guest

    Yes, I mean the code under "Matching against your address space" on
    http://mipagina.cantv.net/lem/perl/iptut.htm. It goes:

    use NetAddr::IP;

    my $space = new NetAddr::IP->new('10.128.0.0/17');

    for my $ip (map { new NetAddr::IP->new($_) } <DATA>)
    {
    print $ip, "\n"
    if $space->contains($ip);
    }

    __DATA__
    172.16.1.1
    172.16.1.5
    ...


    There's a "new" too many in "new NetAddr::IP->new( ...);". I suppose the
    call was originally in indirect object syntax and was re-written to use
    arrow notation. Now it contains both :)

    As I said, it's a trivial error and easily corrected.

    Anno
     
    Anno Siegel, Jul 31, 2004
    #11
  12. Facco Eloelo

    Eric Bohlman Guest

    What advantage does that have over the more traditional use of for() for
    that purpose?
     
    Eric Bohlman, Jul 31, 2004
    #12
  13. Facco Eloelo

    Anno Siegel Guest

    It wasn't my sharp eye but a run time error that alerted me to the bug.

    When I call "new NetAddr::IP->new('10.128.0.0/17')", I get to see "Can't
    call method "new" on an undefined value...". The call translates to
    "'NetAddr::IP'->new->new('10.128.0.0/17')" (Deparse), and since new()
    without arguments returns undef, I can't see how it would ever
    work. So what I see is a fatal error.

    Anno
     
    Anno Siegel, Aug 1, 2004
    #13
  14. Facco Eloelo

    Anno Siegel Guest

    But NetAddr::IP->new() returns undef (experimentally), so the object
    method call doesn't happen. It could work, but in the given case it
    doesn't.

    Anno
     
    Anno Siegel, Aug 1, 2004
    #14
  15. Facco Eloelo

    Anno Siegel Guest

    I agree that one-shot "for" is more frequently seen, but map has
    different properties that may be advantages.

    One is the usual difference between map and for. Map returns a value,
    the statement in for must have a side effect. That's the same, whether
    you use the one-shot form or a real loop.

    Another difference is that map isn't a statement modifier, so you
    can combine it with variable declarations.

    my ( $y) = map ..., $x;

    is fine, but this is disallowed:

    my $y = ... for $x;

    Anno
     
    Anno Siegel, Aug 1, 2004
    #15
  16. Facco Eloelo

    Anno Siegel Guest

    Situation here is Darwin 7.4.0, Perl 5.8.5, NetAddr::IP 3.20.

    A glance at NetAddr::IP shows that new() is prepared to be called as an
    object method, so if the call without an argument happens to return
    an actual object on a system, that would make it appear to work.

    Otherwise, what I see at a glance doesn't make me too happy. The
    new() method has a prototype. There *may* be a good reason for that,
    but I doubt it. I'm afraid the author wasn't aware that prototypes
    have no effect on methods.

    The next few lines contain this sequence:

    my $ip = lc $_[1];
    # ...
    $ip = 'default' unless defined $ip;

    Well, it's too late to check $ip for undef. This doesn't build trust in
    the code.

    Mind you, there can still be a lot of useful knowledge and functionality
    in the module, but I wouldn't be the least surprised if it showed
    irregular behavior under unusual circumstances.

    Anno
     
    Anno Siegel, Aug 1, 2004
    #16
  17. Facco Eloelo

    Uri Guttman Guest

    MG> Wow! Thanks Uri, you're really a master! I don't consider myself
    MG> a perl guru, as a matter of fact, I'm rather far from it, and I'm
    MG> grateful for anything that I can learn.

    then send your praise to damian conway for that little tidbit as i got
    the idea from him. :)

    uri
     
    Uri Guttman, Aug 1, 2004
    #17
  18. Facco Eloelo

    Uri Guttman Guest

    EB> What advantage does that have over the more traditional use of for() for
    EB> that purpose?

    i needed the result of getting stuff FROM $_ and but not modifying
    it. the extract code you pass into Sort::Maker::make_sorter works on $_
    and i needed a simple way to alias the full record to $_ and map was the
    right trick. look at the code to see how i used it to do that.

    uri
     
    Uri Guttman, Aug 1, 2004
    #18
  19. Facco Eloelo

    eloelo Guest


    why these code below can run only once.
    #!/usr/bin/perl
    use NetAddr::IP;

    open(D2,"IPlist");

    open(D3,"IPsegment");
    @line=<D3>;
    $num=@line;

    for($i=0;$i<$num;$i++)
    {
    $segment= $line[$i];
    my $space = NetAddr::IP->new($segment);

    for my $ip (map {NetAddr::IP->new($_) } <D2>)
    {
    print $ip, "\n"
    if $space->contains($ip);
    }
    }


    IPlist
    62.111.0.29
    207.12.133.45
    207.12.133.46

    IPsegment
    62.111.0.0/16
    207.12.0.0/16

    result
    62.111.0.29

    it means the "for"(the external one) loop run only once,why?
     
    eloelo, Aug 1, 2004
    #19
  20. Facco Eloelo

    Anno Siegel Guest

    Well, discouraged. From perlsyn:

    NOTE: The behaviour of a "my" statement modified with a statement modi-
    fier conditional or loop construct (e.g. "my $x if ...") is undefined.
    The value of the "my" variable may be "undef", any previously assigned
    value, or possibly anything else. Don't rely on it. Future versions
    of perl might do something different from the version of perl you try
    it out on. Here be dragons.

    Anno
     
    Anno Siegel, Aug 1, 2004
    #20
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.