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

I started to learn PERL from today...^^
So, my question will be very basic.
Below is my code which reads line-by-line from a file and calculate the sum of the 37th columns.
The problem is that the program doesn't execute "while" loop and directly prints "recv".
I don't know why. Please help me.
---------------------------------------------------------
#!/usr/bin/perl + my $filename ="./multipath.tr"; my @entry; my $size; my $sim_time; my $recv; + $recv = 0; + open(FILE, "<$filename") || die "file $filename can't open : $!"; + while(<FILE>) { print "in while"; @entry = split /\s+/; $size = @entry; print $size; print "\n"; next unless ($size == 51); &get_throughput(@entry); } + sub get_throughput { my $node_id; my $end_point; my $flow_id; my $pkt_id; my $pkt_size; + if($entry[1] == "r") { $sim_time = $entry[3]; $node_id = $entry[5]; $end_point = $entry[39]; $pkt_id = $entry[41]; $pkt_size = $entry[37]; $recv += $pkt_size; } } + + close FILE;> + print $recv; print "\n";

Replies are listed 'Best First'.
Re: What's wrong with my code? [from a beginner]
by holli (Abbot) on Jan 27, 2005 at 19:19 UTC
    the file you try to read is empty.

    Update: Your code can be shortened a lot.
    my $sum; + open(FILE, "<$filename") || die "file $filename can't open : $!"; while(<FILE>) { $sum += ( split /\s+/ )[37]; } close FILE; print $sum;
    or even simpler as a one liner:
    shell> perl -naF\s+ -e "$sum+=$F[2]; END{print $sum}" file

    holli, regexed monk
Re: What's wrong with my code? [from a beginner]
by Roy Johnson (Monsignor) on Jan 27, 2005 at 19:20 UTC
    It works ok for me (except for the extra ">" char on the close line). I made a multipath.tr file consisting of
    one two three
    Of course, this doesn't look like what the program wants to process, so my output is:
    in while...1 in while...1 in while...1 0
    but you can see that it is processing the loop. If your multipath.tr file is empty, the loop would never execute. Is that possibly what's going on?

    Caution: Contents may have been coded under pressure.
Re: What's wrong with my code? [from a beginner]
by punkish (Priest) on Jan 27, 2005 at 20:21 UTC
    I have no idea what your code is doing, but take a look at the following redo. Hopefully it will help.
    #!/usr/bin/perl my $filename ="./multipath.tr"; my $sim_time; my $recv = 0; open(FILE, "<$filename") || die "file $filename can't open : $!"; while(<FILE>) { chomp; my @entry = split /\s+/; print scalar(@entry), "\n"; next unless (scalar(@entry) == 51); get_throughput(\@entry); } close FILE; print $recv, "\n"; sub get_throughput { my $entry = shift; # do you really need all this? # don't seem to be doing anything # with them. my ($node_id, $end_point, $flow_id, $pkt_id); if($entry->[1] eq "r") { $sim_time = $entry->[3]; $node_id = $entry->[5]; $end_point = $entry->[39]; $pkt_id = $entry->[41]; # this is the 38th col. Use element 36 instead. $recv += $entry->[37]; } }
Re: What's wrong with my code? [from a beginner]
by bmann (Priest) on Jan 27, 2005 at 20:01 UTC
    Another thing you will want is to review the difference between numeric comparison and string comparison ( "==" vs "eq", see perlintro )

    if ($entry[1] == "r") # true if $entry[1] is '0', or 'r', or 'z'! if ( $entry[1] eq "r" ) # true if $entry[1] is "r"
    use warnings; will point that out for you when the script runs.
Re: What's wrong with my code? [from a beginner]
by 5mi11er (Deacon) on Jan 27, 2005 at 19:18 UTC
    Update: wrong: Since you've created the array @entry as a 'my' variable, and not passed this variable to your get_throughput routine correctly, and not attempted to get the variable within that routine, the array entry isn't accessable from the routine get_throughput.

    They are correct, the my declaration is still in scope. My bad. </endupdate>

    Simple fix, remove the 'my @entry;' line. entry then becomes global and the routine should work.

    More complex fix: Pass the actual entry array. To do this, it needs to look like this.

    &get_throughput(\@entry); sub get_throughput { my $entryref; foreach $entryref (@_) { ... if($entryref->[1] == "r") { $sim_time = $entryref->[3]; ...
    This iterating over @_ allows you to pass more than one array reference to the subroutine, it will handle as many as you throw at it.

    There are other ways to tackle this as well...

    -Scott

      That is just plain wrong. see this code:
      my @array = (1,2,3); test (); sub test { print $array[0]; } #prints 1

      holli, regexed monk
      The passed argument list is ignored, but the array is within scope, and so is accessible within get_throughput.

      Caution: Contents may have been coded under pressure.
        To clarify passing values to a subroutine
        The arguments for a subroutine are treated as a list assignment to the @_ list. This script demonstrates a few key concepts:

        my @entry = ('ListItem1', 'ListItem2'); $ScalarContext = &get_throughput($Var1, $Var2, @entry, $Var3, \@entry) +; @ListContext = &get_throughput($Var1, $Var2, @entry, $Var3, \@entry); sub get_throughput { my $GetsVar1 = shift @_; #@_ is a list of your arguments my $Scalar = shift; # gets $Var2, @_ is the default for s +hift my ($List1, $List2) = @_; #@_ your list was added to @_ as indi +vidual elements my (undef, undef, $Var3) = @_; #undef discards return values my $ListRef = $_[4]; #a reference to your list #see docs for more info on refs return wantarray ? @list : $Scalar; }
        Ardemus "This, right now, is our lives."