Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

How to reset a variable for each file inside a while( <> ) loop?

by pat_mc (Pilgrim)
on Jun 13, 2008 at 13:59 UTC ( [id://691905]=perlquestion: print w/replies, xml ) Need Help??

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

Hi, All -

Here's a question that I cannot think of an elegant answer for and hope you may be able to help:
$my counter = 0; while ( <> ) { $counter ++; print; }

Now, if this loop is in the body of my programme, it should simply count the lines in a file handed over as an invocation argument to this script. However, if I hand over two or more invocation arguments $counter will not reset to zero when reading in the second, third, etc. file.

Therefore my question: Is there an elegant (!) way to reset the variable back to zero for each file to read in? How can I know that Perl is now accessing the next file in the list of invocation arguments? I was thinking along the lines of a special variable that might change its value when accessing the next file or so.

For purely aesthetic reasons I want to avoid having to write something like this:
for my $file in ( @ARGV ) { open FILE, "<", $file; $my counter = 0; while ( <FILE> ) { $counter ++; print; } ... }


Any ideas on this?

Thanks in advance for your help!

Best regards -

Pat

Replies are listed 'Best First'.
Re: How to reset a variable for each file inside a while( <> ) loop?
by toolic (Bishop) on Jun 13, 2008 at 14:37 UTC
    Straight out of the docs for eof (thanks to the prompt from rminner++):
    while (<>) { print "$.\n"; } continue { close ARGV if eof; # Not eof()! }
      Thanks, toolic - this looks interesting indeed.

      Since I am not familiar with the continue structure, can you please explain what exactly it is doing in your code?

      Thanks again!

      Pat
        I'm glad you asked because, as it turns out, continue is not even needed in this case. Here is the simplified code:
        while (<>) { print "$.\n"; close ARGV if eof; }
        I never use continue either; I just copied the code snippet (and tested it!) from the eof documentation. But, that code also used a next statement, which I deleted since it was not needed for your purposes. I should have also deleted the continue statement. I Read The Free Manual, as I'm sure you also did, which explains the relationship between continue and next.
        The continue allows you to call next in the loop without skipping "close ARGV if eof;".
        The continue allows you to call next in the loop without skipping "close ARGV if eof;".
Re: How to reset a variable for each file inside a while( <> ) loop?
by starX (Chaplain) on Jun 13, 2008 at 14:43 UTC
    Aesthetic reasons not withstanding, I'm not sure how you plan on resetting your counter without keeping track of which file you're working with in some way. There are some other things you might try, but from where I sit, you're going to wind up writing something resembling the code that you're trying to avoid.

    I think there's something in PBP to the effect of "don't be elegant" anyway. The aesthetics you're working with today may not be the aesthetics you're working with a few months from now, or that the next guy uses. The code that you already know how to write and are trying to avoid, on the other hand, is pretty straight forward in what it does. That may be more meaningful for you in the future than whether or not it's pretty.

      Thanks, starXX for your comments and for taking the time to post your reply!

      While I see your point regarding the transient nature of aesthetic standards I am reluctant to agree and gladly retreat to the position that everybody feel free to make their code as (transiently) aesthetic as they please.

      More to the point of my original question, I would be very much interested in the "some other things you might try" that you mentioned. Can you provide details here?

      As you point out correctly, it seems one explicitly would need to keep track of which file Perl is currently working on. I was hoping there is a way around that because implictly the <> operator seems to be knowing which file it is currently processing.
      I am therefore still wondering if Perl provides an access to this 'behind the scene' information at the time of iterating through those input files.

      Thanks again!

      Cheers - Pat
        ...still wondering if Perl provides an access to this 'behind the scene' information

        (from perlvar)

        $ARGV contains the name of the current file when reading from <> +.
Re: How to reset a variable for each file inside a while( <> ) loop?
by rminner (Chaplain) on Jun 13, 2008 at 14:14 UTC
    If you want to print the line number of the current filehandle you can use the variable $. (See also perldoc perlvar - $INPUT_LINE_NUMBER).

        What "perldoc" are you using?

        $ perldoc -v '$.' Ending switch processing. Args are [$.] with 0 errors. /usr/bin/perldoc => Pod::Perldoc v3.14 Formatter class Pod::Perldoc::ToMan successfully loaded! Will format with the class Pod::Perldoc::ToMan Searching for $. Looking for $. in /usr/bin /etc/perl /usr/local/lib/perl/5.8.8 /usr/lo +cal/share/perl/5.8.8 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5. +8 /usr/share/perl/5.8 /usr/local/lib/site_perl . /usr/local/sbin /usr +/local/bin /usr/sbin /usr/bin /sbin /bin /usr/games No documentation found for "$.".

        Update: ferreira has /msg'd me to tell me it's a feature added in recent developer releases. Nice; it's certainly something I've often wanted to be able to do.

      Thanks for this valuable reminder, rminner!

      The only problem I see is that the special variable $. is subject to the very problem I am trying to escape from: it increases across all lines in all files in @ARGV.
Re: How to reset a variable for each file inside a while( <> ) loop?
by cdarke (Prior) on Jun 15, 2008 at 13:35 UTC
    As almut said, $ARGV hold the current file name, so you could get the number of lines for each file into a hash with:
    while (<>) { $lines{$ARGV}++; ... }
    Or use the change in $ARGV to detect a new file, for example to print a banner:
    while (<ARGV>) { if ( $ARGV ne $current_file ) { print "\n","-" x 20, " $ARGV ", "-" x 20, "\n"; $current_file = $ARGV; $files++; } print; }

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://691905]
Approved by Corion
Front-paged by GrandFather
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others lurking in the Monastery: (None)
    As of 2024-04-25 02:05 GMT
    Sections?
    Information?
    Find Nodes?
    Leftovers?
      Voting Booth?

      No recent polls found