开发者

perl help troubleshooting error msg using perl module

I am testing perl script using this example found on the forum. I took the sample data and put it in a separate file and using an open to try it this way.

I don't understand why I would be getting undef. I am getting the msg:

Use of uninitialized value in join or string at ./h.pl line 15, line 4.

#!/usr/local/bin/perl

use warnings;
use strict;
use Data::Dumper;
use Text::CSV_XS;

    open my $fh, '<', 't.out' or die "Unable to open: $!";
    my $csv = Text::CSV_XS->new( { sep_char => "\t" } );
    my @list;
    $csv->column_names ($csv->getline ($fh));
    while ( my $hr = $csv->getline_hr($fh) ) {
        push @list, $hr->{'Ball'};
    开发者_StackOverflow}

    print "@list\n";
    print Dumper(\@list);

Test file (t.out)

Camera Make Camera Model    Text    Ball    Swing
a   b   c   d   e
f   g   h   i   j
k   l   m   n   o


$ od -cx t.out 
0000000   C   a   m   e   r   a       M   a   k   e  \t   C   a   m   e
        6143 656d 6172 4d20 6b61 0965 6143 656d
0000020   r   a       M   o   d   e   l  \t   T   e   x   t  \t   B   a
        6172 4d20 646f 6c65 5409 7865 0974 6142
0000040   l   l  \t   S   w   i   n   g  \n   a  \t   b  \t   c  \t   d
        6c6c 5309 6977 676e 610a 6209 6309 6409
0000060  \t   e  \n   f  \t   g  \t   h  \t   i  \t   j  \n   k  \t   l
        6509 660a 6709 6809 6909 6a09 6b0a 6c09
0000100  \t   m  \t   n  \t   o  \n  \0
        6d09 6e09 6f09 000a
0000107

Results:

$VAR1 = [
          undef,
          undef,
          undef
        ];


If $csv->getline_hr($fh) returns an undefined value, you will get the warning "Use of uninitialized value in join or string at ..." if you try to print the list @list.

You can test this explicitly with a simple program:

use strict;
use warnings;
my @list;
my $x = undef; # This is similar to what may happen in your program on the `push @list, @hr->{'Name'}` line
push @list, $x;
print "@list\n";

Also, you may want to use Data::Dumper and then print Dumper(\@list) instead if you are just doing debugging, since you won't get any warnings, and you will get a clearer picture of what is stored in your data structure.


In the question you refer to, I also wrote this on the last line:

ETA: If you're going to cut & paste to try it out, make sure that the tabs are carried over in the data.

Did you make sure that your tabs survived the copy/paste into your file 't.out'?

This module is rather unforgiving about bad formats in the data file.

Update:

Be aware that a field such as 'Ball ' will be considered different than 'Ball'. I.e. if you have additional whitespace, it will screw things up.

What you may try out to correct that is adding allow_whitespace => 1, to the options of the $csv object. This will correct any subtle whitespace errors in your input file.

You can also check for format errors by printing the header keys with

print Dumper $csv->column_names(); 


As others have mentioned, it is very possible that @list never got a value in it. If $csv->getline_hr($fh) returns an undef the first time through, you'll never push anything into @list.

There are two things you can do:

  1. You can test if @list is uninitialized before printing it
  2. You can loosen the use warnings pragma not to include uninitialized warnings:

Here's how you can do your testing:

if (@list) {
   print "List = " . @list . "\n";
} 
else {
   print "List has no values\n";
}

You can use scalar @list as Igor Zinov'yev shows, but that's not really necessary in this case and I think the simple if (@list) is clearer. You can also use if (defined @list) which is very clear, but has been discouraged over the last few years.

If this is a temporary thing (just seeing if your code works or not), you can loosen the use of strict:

no warnings qw(uninitialized);
print "@list\n";   #Now you won't get a warning if @list has no value
use warnings;      #Turn the warnings back on. It helps you code better

A slight Word 'o Warning: In this case, your statement won't print anything and that might confuse you even more. Always put a prompt of some sort to make sure something prints:

print "\@list = @list\n";

I prefer this as a temporary solution when I'm printing out a lot of debugging statements which I'll later remove. In fact, I'll create a special debug subroutine for these types of messages:

use strict;
use warnings;
use constant DEBUG_LEVEL => 1;  #0 = no debug messages 1 = debug messages

[...]
while (yadda, yadda, yadda) {
   push @list, $hr->{Name};
}
debug (qq(\@list = ") . join "|", @list . qq("));

[...]

sub debug {
   my $message = shift;

   return if (not DEBUG_LEVEL);
   no warnings qw(uninitialized);
   print qq(DEBUG: $message\n);
   use warnings;      #Not really needed since the code block ends
   return $message;
}


It seems like your @list array is undefined. Try checking it:

if (scalar @list) {
    print "@list\n";
}

If your while loop has never been executed, scalar @list will return 0, because the array is empty.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜