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

Hey Monks,

I have the following code:

my $ip = qr/\b192.168.3.5\b/; my $line = 0; my @fwlog; my $logfile = "/tmp/05jul01.drop"; open LOG, "$logfile" or die "Can't open $logfile: $!\n"; while ($line=<LOG>){ chomp($line); while($line =~ $ip) { print "$line\n"; #push (@fwlog,$line); } } close LOG; #print "@fwlog\n";

This works if I just print $line in the loop, but I want to save the results of $line to a variable so that I can use it outside of the while loop. As you can see, I tried a few different things with push, but that did not work. What is the best way of accomplishing this?

Thanks,
Dru

Replies are listed 'Best First'.
Re: Saving Results of a while loop
by arturo (Vicar) on Aug 01, 2001 at 18:44 UTC

    You shouldn't have that inner while. I'd just make it

    if ( $line =~ $ip ) { push (@fwlog, $line); print "$line"; }

    or equivalent.

    You might also try changing that final print to read

    print "$_\n" foreach ( @fwlog );

    but you should be getting *some* output.

    An alternate approach: if the file isn't really large, you could suck it into memory and put the matching lines into an array, á la:

    open LOG, "$logfile" or die "Can't open $logfile: $!\n"; my @fwlog = grep { $ip } <LOG>; close LOG;

    that grep line will grab just the lines from the file that match. To remove the newlines from those, you can just chomp the whole array.

    Finally, note that the "." has special meaning. That regex will match "192a168b3c5", so to make sure you're just getting the IP you're looking for, escape those dots.

    HTH!

    perl -e 'print "How sweet does a rose smell? "; chomp ($n = <STDIN>); +$rose = "smells sweet to degree $n"; *other_name = *rose; print "$oth +er_name\n"'
Re: Saving Results of a while loop
by tachyon (Chancellor) on Aug 01, 2001 at 19:15 UTC

    This incorporates all the relevant features and fixes mentioned above. The quotemeta escapes the . chars in the regex which would otherwise match anything. We use $_ in the while loop that iterates over our logfile as this a normal perl idiom. This lets us use m/blah/ as this is the same as $_ =~ m/blah/. We can compile once using /o so don't need to use qr. By not chomping off the newlines in the first place you don't need to put them back again, so print @fwlog is all you need as the newlines are still there.

    my $ip = "192.168.3.5"; $ip = quotemeta $ip; my @fwlog; my $logfile = "/tmp/05jul01.drop"; open LOG, "$logfile" or die "Can't open $logfile: $!\n"; while (<LOG>){ push @fwlog,$_ if m/\b$ip\b/o; } close LOG; print @fwlog;

    Hope this helps

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: Saving Results of a while loop
by VSarkiss (Monsignor) on Aug 01, 2001 at 18:42 UTC

    I'm not sure exactly what problem you're having, but this code does have a couple of things wrong with it:

    • The innermost while loop never terminates since you don't change $line within it.
    • You want to escape the dots in your IP address: $ip = qr/\b192\.168\.3\.5\b/;

    Try fixing these up, because your idea of saving the values in an array should do what you want. If this doesn't fix it, describe the error a little more specifically, and someone here will probably be able to help more.

    HTH

      Update:
      As Hofmator was kind enough to point out, I was confusing qr with quotemeta, which are two entirely different beasties, though for some reason I had the two confused.

      Using \Q and \E is still one way to avoid having to go backslash crazy on your regex, though, and this was the original inspiration for this follow-up.

      The original post is preserved below.
      Using qr() on \b is going to look for "backslash,b" instead of a word break. Try this instead:
      $ip = "192.168.3.5"; # ... if ($line =~ /\b\Q$ip\E\b/) { # ... }
      Using \Q and \E ensure that no matter what $ip has in it, it will be matched very literally. You could also take this approach:
      $ip = qr("192.168.3.5"); # ... if ($line =~ /\b$ip\b/) { # ... }
      This makes sure that $ip is "regex-ready" before being used, by virtue of the qr() function.

        Well, I have to say no and no

        1. qr// works fine with \b, e.g.
          my $string = q/This is a test./; my $regex1 = qr(\bis); my $regex2 = qr(is); print $string =~ /$regex1/g, "\n"; print $string =~ /$regex2/g, "\n"; # prints is isis
        2. Your second part
          $ip = qr("192.168.3.5");
          matches e.g. "192 16833!5" but not what was being looked for. Did you maybe want to use the quotemeta function?? Then
          my $ip = "192.168.3.5"; $ip = quotemeta $ip;
          would be the way to go.

        -- Hofmator

(ichimunki) Re: Saving Results of a while loop
by ichimunki (Priest) on Aug 01, 2001 at 18:48 UTC
    I don't think your second while condition is ever evaluating to true. If it did, you'd get into an infinite loop, since you never change either $line or $ip and you provide no exit. Change that second while to an if first.

    Next you may want to consider how you are setting up your $line to $ip comparison. Why not set $ip with $ip=quotemeta '192.168.3.5' then use if ($line =~ /\b$ip\b/) for your condition?

    There is nothing wrong with your push statement or the scoping issues surrounding what you want to do.

    update: added quotemeta after seeing tachyon's post.
Re: Saving Results of a while loop
by rob_au (Abbot) on Aug 01, 2001 at 18:37 UTC
    You've definitely got the right idea there - I too would be pushing the results into an array if I needed to reference them later in the program. But instead of the print "@fwlog\n"; line, I think you might be looking for something like this:
    print join("\n", @fwlog), "\n";
    ... or ...
    print $_, "\n" foreach @fwlog;
    Both of which will print each element of the @fwlog array, which of course is comprised of the $line elements push-ed into it. If this doesn't work for you in the context that you need it, /msg me and together I'm sure that we could cook up something that meets jyour needs.
     

     
    Ooohhh, Rob no beer function well without!