confusing filehandle in perl

半世苍凉 提交于 2019-12-04 06:07:44

问题


Have been playing with the following script but still couldn't understand the meaning behind the two different "kinds" of filehandle forms. Any insight will be hugely appreciated.

#! usr/bin/perl
use warnings;
use strict;
open (FH, "example.txt") or die $!;

while (<FH>) {
    my @line = split (/\t/, $_); {
        print "@line","\n";
    }
}

The output is as expected: @line array contains elements from line 1,2,3 ... from example.txt. As I was told that open (FH, example.txt) is not as good as open (my $fh, '<', 'example.txt'), I changed it but then confusion arose.

From what I found, $fh is scalar and contains ALL info in example.txt. When I assigned an array to $fh, the array stored each line in example.txt as a component in the array. However, when I tried to further split the component into "more components", I got the error/warning message "use of uninitialized value". Below is the actual script that shows the error/warning message.

open (my $fh, '<', 'example.txt') or die $!;
foreach ($fh) {
    my @line = <$fh>;
    my $count = 0;
    for $count (0..$#line) {
        my @line2 = split /\t/, $line[$count];
        print "@line2";
        print "$line2[0]";
        }
    }

print "@line2" shows the expected output but print "$line2[0]" invokes the error/warning message. I thought if @line2 is a true array, $line2[0] should be okay. But why "uninitialized value" ??

Any help will be appreciated. Thank you very much.

Added - the following is the "actual" script (I re-ran it and the warning was there)

#! usr/bin/perl
use warnings;
use strict;
open (my $fh, '<', 'example.txt') or die $!;

foreach ($fh) {
    my @line = <$fh>;
    print "$line[1]";
    my $count = 0;
    for my $count (0..$#line) {
    my @line2 = split /\t/, $line[$count];
    print "@line2";
    #my $line2_count = $#line2;
    #print $line2_count;
    print "$line2[3]";
    }
    }

The warning is still use of uninitialized value $line2[3] in string at filename.pl line 15, <$fh> line3.


回答1:


In your second example, you are reading the filehandle in a list context, which I think is the root of your problem.

my $line = <$fh>;

Reads one line from the filehandle.

my @lines = <$fh>;

Reads all the file. Your former example, thanks to the

while (<FH>) {

Is effectively doing the first case.

But in the second example, you are doing the second thing.




回答2:


AFAIK, you should always use

while (<FH>) {
   # use $_ to access the content
}

or better

while(my $single_line = <FH>) {
   # use $single_line to access the content
}

because while reads line by line where for first loads all in memory and iterates it after.

Even the returns undef on EOF or error, the check for undef is added by the interpreter when not explicitly done.

So with while you can load multi gigabyte log files without any issue and without wasting RAM where you can't with for loops that require arrays to be iterated.

At least this is how I remember it from a Perl book that I read some years ago.



来源:https://stackoverflow.com/questions/30684525/confusing-filehandle-in-perl

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!