http://www.perlmonks.org?node_id=1001549

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

Hello everyone, I recently learned that you can get the amount of lines in a file by doing this:

@temp = <$file> # file is the file handle $lines = scalar @temp

The only need for @temp here is so that scalar can read <$file> as an array. Technically, I could just write "$lines = scalar( <$file> )" or "$lines = @{[ (<$file>) ]}". The problem is that the former doesn't work, and the latter gives $lines = 1.

How do I shrink that chunk of code into a one liner?

Replies are listed 'Best First'.
Re: Forcing array context on a file handle
by BrowserUk (Patriarch) on Oct 30, 2012 at 21:05 UTC

    If there's any chance that the file can be of any real size at all, and you only want the line count, you'd be much better off using:

    my $lines; ++$lines while <$file>;

    Building a potentially huge list only to throw it away, just to count the lines, will be very costly in terms of time and memory.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

    RIP Neil Armstrong

      Or even
      1 while <$file>; print $.;
      لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

        Indeed. But that's idiomatic, so lisp programmers probably won't understand it and PerlCritic would probably have an apoplectic hissy fit.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        RIP Neil Armstrong

Re: Forcing array context on a file handle
by tobyink (Canon) on Oct 30, 2012 at 20:53 UTC
    my $lines =()= <$file>;
    perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'
Re: Forcing array context on a file handle
by toolic (Bishop) on Oct 30, 2012 at 20:56 UTC
    "$lines = @{[ (<$file>) ]}".The problem is that the former doesn't work, and the latter gives $lines = 1.
    Your 2nd example gives me the correct number of lines (not 1):
    use warnings; use strict; open my $file, '<', $0; my $lines = @{[ (<$file>) ]}; print "$lines\n";

    The output for me is 5.

      Yes, I was a bit surprised by the assertion that this didn't work. I can only suppose the OP forgot the angled brackets when testing.

      perl -E'sub Monkey::do{say$_,for@_,do{($monkey=[caller(0)]->[3])=~s{::}{ }and$monkey}}"Monkey say"->Monkey::do'

      That's odd. It works for me too, but it doesn't work in my larger program (I have all the brackets, and in the right order). I have some extra stuff going around with the file handle, so maybe that's what's causing trouble.

      I ended up going with BowserUK's solution, which is slightly shorter than the method I was using before.

        After you read a file you have to rewind it with seek if you want to read it again from the beginning. Here is how to set the filehandle back to the beginning of the file.

        seek $fh, 0, 0;
Re: Forcing array context on a file handle
by fishmonger (Chaplain) on Oct 30, 2012 at 21:11 UTC
    Did you check perldoc? This is a FAQ

    perldoc -q "How do I count the number of lines in a file"

      Hi, ronmrdechai

      $lines = grep {$_} <$file>;
        That works for files in the default case, because every line will have a newline or somesuch, and will not be an empty string. For counting, map would be more appropriate than grep. But tobyink showed the idiom above:
        my $lines =()= <$file>;

        -QM
        --
        Quantum Mechanics: The dreams stuff is made of