http://qs321.pair.com?node_id=984657

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

Is it possible to count the number of hops in each traceroute if my file looks like this, i tried using a for loop but its not working that way

use Geo::IPfree; use Regexp::Common qw/net/; use warnings; use strict; system("clear"); my $file2 = 'Traces.txt'; open my $in, '<', $file2 or die $!; open my $out, '>', 'To. of Traceroutes' or die $!; my $text = "End of Route"; my $var=0; while (my $line = <$in>) { if($line =~ /traceroute/){ #print $line; $var++;#just shows how many traceroutes are there in the f +ile print {$out} "*End*\n"; } } print "$var \n";

Input file looks like this (the number of hops is the numbered IPs) So i want to find hops for each traceroute

Traceroute: 11 1291796822 1291796821 1291796821 OpenDNS 0.chstatic.cvc +dn.com 216.137.61.109 traceroute to 216.137.61.109 (216.137.61.109), 30 hops max, 60 byte pa +ckets 1 192.168.178.1 0.638 ms 7.361 ms 7.366 ms 2 82.135.16.28 44.925 ms 46.633 ms 50.457 ms 3 212.18.7.121 98.010 ms 98.307 ms 98.650 ms 4 212.18.6.97 68.374 ms 72.222 ms 76.184 ms 5 62.140.24.49 129.246 ms 130.224 ms 130.221 ms 6 4.69.134.2 98.205 ms 105.207 ms 102.287 ms 7 4.69.140.10 106.816 ms 82.609 ms 4.69.140.2 88.631 ms 8 4.68.23.76 79.559 ms 65.093 ms 4.68.23.204 64.530 ms 9 212.162.24.70 65.476 ms 50.797 ms 55.108 ms 10 216.137.61.109 58.221 ms 62.351 ms 59.094 ms Query: 18 1291796822 GoogleDNS 0.chstatic.cvcdn.com 1 True 0.155671834 +946 0.0507638454437 Traceroute: 2 1291796823 1291796822 1291796822 LocalDNS LocalDNS 192.1 +68.178.1 traceroute to 192.168.178.1 (192.168.178.1), 30 hops max, 60 byte pack +ets 1 192.168.178.1 0.649 ms 1.033 ms 1.013 ms Query: 13 1291796823 LocalDNS 0.media.collegehumor.com 1 True 0.193642 +139435 0.0472960472107 Traceroute: 9 1291796827 1291796822 1291796822 GoogleDNS GoogleDNS 8.8 +.8.8 traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets 1 192.168.178.1 0.464 ms * * 2 82.135.16.28 68.613 ms 72.079 ms 76.268 ms 3 212.18.7.101 160.966 ms 163.495 ms 163.517 ms 4 93.104.240.53 99.638 ms 103.396 ms 108.241 ms 5 209.85.241.110 111.919 ms 209.85.240.64 114.900 ms 209.85.241.11 +0 119.654 ms 6 209.85.254.116 124.134 ms 209.85.254.118 127.998 ms 209.85.254.1 +12 111.621 ms 7 209.85.249.166 116.258 ms 209.85.254.126 115.774 ms 209.85.254.1 +34 105.670 ms 8 8.8.8.8 95.428 ms 95.573 ms 95.923 ms Query: 10 1291796827 OpenDNS 1.im.cz 1 True 0.0573320388794 0.05522108 +078

Replies are listed 'Best First'.
Re: Can I count lines in a substring?
by davido (Cardinal) on Jul 31, 2012 at 21:26 UTC

    I like to try to find some trigger that I can consider to be a record separator, and then use $/ accordingly. Here's an example wherein we use Traceroute: as the record separator. That means that the first record will be empty, since technically it shows up at the beginning of a record rather than at the end. After discarding the record separator, we can check to see if the rest of the record is empty (it will be in the case of the first time Traceroute: is seen, since nothing precedes it).

    Next, in this example, we find another anchor and use it to locate the IP address that we're trying to reach. Capture that. Then count how many times a number appears at the beginning of a line (preceded by an optional space). Keep track of that count. The Lingua::EN::Inflect stuff is just for fun.

    use Lingua::EN::Inflect qw( PL ); { local $/ = 'Traceroute'; while( my $line = <DATA> ) { chomp $line; next unless length $line; my ( $destination ) = $line =~ m/\(([^)]+)\)/; my $count = () = $line =~ m/^\s*(\d+)\s{2}/mg; print "$destination: $count ", PL( "hop", $count ), ".\n"; } } __DATA__ Traceroute: 11 1291796822 1291796821 1291796821 OpenDNS 0.chstatic.cvc +dn.com 216.137.61.109 traceroute to 216.137.61.109 (216.137.61.109), 30 hops max, 60 byte pa +ckets 1 192.168.178.1 0.638 ms 7.361 ms 7.366 ms 2 82.135.16.28 44.925 ms 46.633 ms 50.457 ms 3 212.18.7.121 98.010 ms 98.307 ms 98.650 ms 4 212.18.6.97 68.374 ms 72.222 ms 76.184 ms 5 62.140.24.49 129.246 ms 130.224 ms 130.221 ms 6 4.69.134.2 98.205 ms 105.207 ms 102.287 ms 7 4.69.140.10 106.816 ms 82.609 ms 4.69.140.2 88.631 ms 8 4.68.23.76 79.559 ms 65.093 ms 4.68.23.204 64.530 ms 9 212.162.24.70 65.476 ms 50.797 ms 55.108 ms 10 216.137.61.109 58.221 ms 62.351 ms 59.094 ms Query: 18 1291796822 GoogleDNS 0.chstatic.cvcdn.com 1 True 0.155671834 +946 0.0507638454437 Traceroute: 2 1291796823 1291796822 1291796822 LocalDNS LocalDNS 192.1 +68.178.1 traceroute to 192.168.178.1 (192.168.178.1), 30 hops max, 60 byte pack +ets 1 192.168.178.1 0.649 ms 1.033 ms 1.013 ms Query: 13 1291796823 LocalDNS 0.media.collegehumor.com 1 True 0.193642 +139435 0.0472960472107 Traceroute: 9 1291796827 1291796822 1291796822 GoogleDNS GoogleDNS 8.8 +.8.8 traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets 1 192.168.178.1 0.464 ms * * 2 82.135.16.28 68.613 ms 72.079 ms 76.268 ms 3 212.18.7.101 160.966 ms 163.495 ms 163.517 ms 4 93.104.240.53 99.638 ms 103.396 ms 108.241 ms 5 209.85.241.110 111.919 ms 209.85.240.64 114.900 ms 209.85.241.11 +0 119.654 ms 6 209.85.254.116 124.134 ms 209.85.254.118 127.998 ms 209.85.254.1 +12 111.621 ms 7 209.85.249.166 116.258 ms 209.85.254.126 115.774 ms 209.85.254.1 +34 105.670 ms 8 8.8.8.8 95.428 ms 95.573 ms 95.923 ms Query: 10 1291796827 OpenDNS 1.im.cz 1 True 0.0573320388794 0.05522108 +078

    The output:

    216.137.61.109: 10 hops. 192.168.178.1: 1 hop. 8.8.8.8: 8 hops.

    Dave

Re: Can I count lines in a substring?
by suaveant (Parson) on Jul 31, 2012 at 20:29 UTC
    Certainly you can, and there are any number of ways to do it. One of the simplest might be to read in the whole file and split it on /^Traceroute:/xms and work with the chunks, but if the file is large (or could be large in the future) that may not be the best method. Going with what you have now I'd say do something like...
    while (my $line = <$in>) { if($line =~ /^traceroute to (\S+)/) { $current_traceroute = $1; $count = 0; #reset the count; print "Trace for $current_traceroute: "; } elsif($line =~ /^\s*\d+\s+/) { $count++; } elsif($line =~ /^Query:/) { print "$count\n"; } }
    Basically you want to catch the beginning (and end) of each block and reset things to start a new count and/or pull any other relevant data. If Query: isn't reliably there then you might have to rely on "Traceroute:" or "traceroute to" to signal the end of the previous call, but then you'd have to handle the last route by triggering on eof since there would be no final "Traceroute:". Make sense?

                    - Ant
                    - Some of my best work - (1 2 3)

Re: Can I count lines in a substring?
by aaron_baugher (Curate) on Aug 01, 2012 at 00:05 UTC

    Unless I'm missing something, the program that creates this file is already counting the hops for you. Each section starts with a line that begins with Traceroute:, followed by the number of hops plus 1, and ending in the destination IP address. That being the case, I'd just go through the file watching for those lines; no counting necessary:

    #!/usr/bin/env perl use Modern::Perl; my $count = 0; while(<DATA>){ if( /^Traceroute: (\d+) .+ (\d+\.\d+\.\d+\.\d+)$/ ){ my $h = $1 - 1; say "$h hop". ($h==1 ? '' : 's') . " to $2"; $count++; } } say "--- $count traces found ---"; __DATA__ Traceroute: 11 1291796822 1291796821 1291796821 OpenDNS 0.chstatic.cvc +dn.com 216.137.61.109 traceroute to 216.137.61.109 (216.137.61.109), 30 hops max, 60 byte pa +ckets 1 192.168.178.1 0.638 ms 7.361 ms 7.366 ms 2 82.135.16.28 44.925 ms 46.633 ms 50.457 ms 3 212.18.7.121 98.010 ms 98.307 ms 98.650 ms 4 212.18.6.97 68.374 ms 72.222 ms 76.184 ms 5 62.140.24.49 129.246 ms 130.224 ms 130.221 ms 6 4.69.134.2 98.205 ms 105.207 ms 102.287 ms 7 4.69.140.10 106.816 ms 82.609 ms 4.69.140.2 88.631 ms 8 4.68.23.76 79.559 ms 65.093 ms 4.68.23.204 64.530 ms 9 212.162.24.70 65.476 ms 50.797 ms 55.108 ms 10 216.137.61.109 58.221 ms 62.351 ms 59.094 ms Query: 18 1291796822 GoogleDNS 0.chstatic.cvcdn.com 1 True 0.155671834 +946 0.0507638454437 Traceroute: 2 1291796823 1291796822 1291796822 LocalDNS LocalDNS 192.1 +68.178.1 traceroute to 192.168.178.1 (192.168.178.1), 30 hops max, 60 byte pack +ets 1 192.168.178.1 0.649 ms 1.033 ms 1.013 ms Query: 13 1291796823 LocalDNS 0.media.collegehumor.com 1 True 0.193642 +139435 0.0472960472107 Traceroute: 9 1291796827 1291796822 1291796822 GoogleDNS GoogleDNS 8.8 +.8.8 traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets 1 192.168.178.1 0.464 ms * * 2 82.135.16.28 68.613 ms 72.079 ms 76.268 ms 3 212.18.7.101 160.966 ms 163.495 ms 163.517 ms 4 93.104.240.53 99.638 ms 103.396 ms 108.241 ms 5 209.85.241.110 111.919 ms 209.85.240.64 114.900 ms 209.85.241.11 +0 119.654 ms 6 209.85.254.116 124.134 ms 209.85.254.118 127.998 ms 209.85.254.1 +12 111.621 ms 7 209.85.249.166 116.258 ms 209.85.254.126 115.774 ms 209.85.254.1 +34 105.670 ms 8 8.8.8.8 95.428 ms 95.573 ms 95.923 ms Query: 10 1291796827 OpenDNS 1.im.cz 1 True 0.0573320388794 0.05522108 +078

    Aaron B.
    Available for small or large Perl jobs; see my home node.

Re: Can I count lines in a substring?
by 2teez (Vicar) on Jul 31, 2012 at 21:35 UTC

    Of course, the old fashion hash is always here to help

    use warnings; use strict; my $router_route = {}; ## an hash ref my $name = ""; while (<DATA>) { s{^\s+|\s+$}{}; # remove the first and trailing spaces if (/^traceroute to.+?\((.+?)\).+?$/s) { $name = $1; } ++$router_route->{$name} if /^\d/; } print "ROUTE\t\t\tNUMBER OF HOPS\n"; my $grand_total_hops = 0; foreach my $route ( keys %{$router_route} ) { $grand_total_hops += $router_route->{$route}; printf "%s\t\t%s\n", $route, $router_route->{$route}; } print "\nTOTAL HOPS\t\t", $grand_total_hops, $/; __DATA__ Traceroute: 11 1291796822 1291796821 1291796821 OpenDNS 0.chstatic.cvc +dn.com 216.137.61.109 traceroute to 216.137.61.109 (216.137.61.109), 30 hops max, 60 byte pa +ckets 1 192.168.178.1 0.638 ms 7.361 ms 7.366 ms 2 82.135.16.28 44.925 ms 46.633 ms 50.457 ms 3 212.18.7.121 98.010 ms 98.307 ms 98.650 ms 4 212.18.6.97 68.374 ms 72.222 ms 76.184 ms 5 62.140.24.49 129.246 ms 130.224 ms 130.221 ms 6 4.69.134.2 98.205 ms 105.207 ms 102.287 ms 7 4.69.140.10 106.816 ms 82.609 ms 4.69.140.2 88.631 ms 8 4.68.23.76 79.559 ms 65.093 ms 4.68.23.204 64.530 ms 9 212.162.24.70 65.476 ms 50.797 ms 55.108 ms 10 216.137.61.109 58.221 ms 62.351 ms 59.094 ms Query: 18 1291796822 GoogleDNS 0.chstatic.cvcdn.com 1 True 0.155671834 +946 0.0507638454437 Traceroute: 2 1291796823 1291796822 1291796822 LocalDNS LocalDNS 192.1 +68.178.1 traceroute to 192.168.178.1 (192.168.178.1), 30 hops max, 60 byte pack +ets 1 192.168.178.1 0.649 ms 1.033 ms 1.013 ms Query: 13 1291796823 LocalDNS 0.media.collegehumor.com 1 True 0.193642 +139435 0.0472960472107 Traceroute: 9 1291796827 1291796822 1291796822 GoogleDNS GoogleDNS 8.8 +.8.8 traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets 1 192.168.178.1 0.464 ms * * 2 82.135.16.28 68.613 ms 72.079 ms 76.268 ms 3 212.18.7.101 160.966 ms 163.495 ms 163.517 ms 4 93.104.240.53 99.638 ms 103.396 ms 108.241 ms 5 209.85.241.110 111.919 ms 209.85.240.64 114.900 ms 209.85.241.11 +0 119.654 ms 6 209.85.254.116 124.134 ms 209.85.254.118 127.998 ms 209.85.254.1 +12 111.621 ms 7 209.85.249.166 116.258 ms 209.85.254.126 115.774 ms 209.85.254.1 +34 105.670 ms 8 8.8.8.8 95.428 ms 95.573 ms 95.923 ms Query: 10 1291796827 OpenDNS 1.im.cz 1 True 0.0573320388794 0.05522108 +078
    OUTPUT
    ROUTE NUMBER OF HOPS 216.137.61.109 10 8.8.8.8 8 192.168.178.1 1 TOTAL HOPS 19

Re: Can I count lines in a substring?
by Kenosis (Priest) on Jul 31, 2012 at 23:16 UTC

    Since each hop is counted, one option is to capture the "traceroute to" IP and its associated final hop count within each 'traceroute to ' record:

    use Modern::Perl; use Lingua::EN::Inflect qw( PL ); { local $/ = 'traceroute to '; /([\d.]+).*?(\d+)[^\n]+\nQ/s and say "$1: $2 " . PL( 'hop', $2 ) for <DATA>; } __DATA__ Traceroute: 11 1291796822 1291796821 1291796821 OpenDNS 0.chstatic.cvc +dn.com 216.137.61.109 traceroute to 216.137.61.109 (216.137.61.109), 30 hops max, 60 byte pa +ckets 1 192.168.178.1 0.638 ms 7.361 ms 7.366 ms 2 82.135.16.28 44.925 ms 46.633 ms 50.457 ms 3 212.18.7.121 98.010 ms 98.307 ms 98.650 ms 4 212.18.6.97 68.374 ms 72.222 ms 76.184 ms 5 62.140.24.49 129.246 ms 130.224 ms 130.221 ms 6 4.69.134.2 98.205 ms 105.207 ms 102.287 ms 7 4.69.140.10 106.816 ms 82.609 ms 4.69.140.2 88.631 ms 8 4.68.23.76 79.559 ms 65.093 ms 4.68.23.204 64.530 ms 9 212.162.24.70 65.476 ms 50.797 ms 55.108 ms 10 216.137.61.109 58.221 ms 62.351 ms 59.094 ms Query: 18 1291796822 GoogleDNS 0.chstatic.cvcdn.com 1 True 0.155671834 +946 0.0507638454437 Traceroute: 2 1291796823 1291796822 1291796822 LocalDNS LocalDNS 192.1 +68.178.1 traceroute to 192.168.178.1 (192.168.178.1), 30 hops max, 60 byte pack +ets 1 192.168.178.1 0.649 ms 1.033 ms 1.013 ms Query: 13 1291796823 LocalDNS 0.media.collegehumor.com 1 True 0.193642 +139435 0.0472960472107 Traceroute: 9 1291796827 1291796822 1291796822 GoogleDNS GoogleDNS 8.8 +.8.8 traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets 1 192.168.178.1 0.464 ms * * 2 82.135.16.28 68.613 ms 72.079 ms 76.268 ms 3 212.18.7.101 160.966 ms 163.495 ms 163.517 ms 4 93.104.240.53 99.638 ms 103.396 ms 108.241 ms 5 209.85.241.110 111.919 ms 209.85.240.64 114.900 ms 209.85.241.11 +0 119.654 ms 6 209.85.254.116 124.134 ms 209.85.254.118 127.998 ms 209.85.254.1 +12 111.621 ms 7 209.85.249.166 116.258 ms 209.85.254.126 115.774 ms 209.85.254.1 +34 105.670 ms 8 8.8.8.8 95.428 ms 95.573 ms 95.923 ms Query: 10 1291796827 OpenDNS 1.im.cz 1 True 0.0573320388794 0.05522108 +078

    Output:

    216.137.61.109: 10 hops 192.168.178.1: 1 hop 8.8.8.8: 8 hops

    Hope this helps!

    ps Thank you, davido: I couldn't resist your use of Lingua::EN::Inflect