Your code as posted works:
use strict;
use Getopt::Std;
my $input_file = $ARGV[0];
my @data = read_data_from_csv($input_file);
sub read_data_from_csv {
my ($fh) = @_;
my @d = ();
#open(FH, "<$fh") || die "Error: no open for $fh: $!";
while (<DATA>) {
chomp;
my @list = split(/,/);
my ($aa) = $list[0];
my ($bb) = $list[1];
my ($cc) = $list[4];
push( @d, ( $aa, $bb, $cc ) );
}
close(FH);
return @d;
}
print "@data\n";
__DATA__
aa ,1 ,no ,ed ,8
bb ,2 ,yes ,ed ,10
cc ,3 ,no ,ed ,12
dd ,4 ,yes ,ed ,13
Output:
aa 1 8 bb 2 10 cc 3 12 dd 4 13
I would suggest you need to check your input file - if on unix, try cat -v which might show you you've got bad line endings.
An easy fix if you do have this problem (or to test it) is include:
s/[\r\n]//g;
More generally though I think there's a few errors in your code - that 'push' for example, probably isn't doing what you're thinking, because you're compressing your CSV into a flat array.
I'd also suggest using Data::Dumper to test outputs, because it's clearer what's happening:
$VAR1 = [
' aa ',
'1 ',
'8 ',
' bb ',
'2 ',
'10',
' cc ',
'3 ',
'12',
'dd ',
'4 ',
'13'
];
As you can see, you've flattened your data, which I am assuming isn't what you want, based on what your write in push.
So you might want to consider using [] instead, because then you get:
$VAR1 = [
[
' aa ',
'1 ',
'8 '
],
[
' bb ',
'2 ',
'10'
],
[
' cc ',
'3 ',
'12'
],
[
'dd ',
'4 ',
'13'
]
];
You can also direct assign array slices, rather than having a 1-1:
push ( @d, [ @list[0,1,4] ] );
Also as a final point - it's bad style to use single letter variables, and you should also use warnings;.
Giving you:
use strict;
use Getopt::Std;
use warnings;
use Data::Dumper;
my $input_file = $ARGV[0];
my @data = read_data_from_csv($input_file);
sub read_data_from_csv {
my ($fh) = @_;
my @d = ();
##NB Commented out so I can use inline data
#open(FH, "<$fh") || die "Error: no open for $fh: $!";
while (<DATA>) {
chomp;
s/[\r\n]//g;
my @list = split(/,/);
push( @d, [ @list[0,1,4] ]);
}
##close(FH);
return @d;
}
print Dumper \@data;
__DATA__
aa ,1 ,no ,ed ,8
bb ,2 ,yes ,ed ,10
cc ,3 ,no ,ed ,12
dd ,4 ,yes ,ed ,13
You might want to consider that instead of opening the file specified in $ARGV[0] this is precisely what the 'magic' file handle <> does. It opens file specified on command line and iterates them, but it also allows you to 'pipe' into the process on STDIN:
Making your program:
#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
## flattened array
my @data_A = map { s/[\r\n]//g; ( split(/,/) ) [0,1,4] } <>;
## preserving structure
my @data_B = map { s/[\r\n]//g; [( split(/,/) ) [0,1,4]] } <>;
print Dumper \@data_B;
I appreciate your code is probably a reduction of the core problem, but I'm just wanting to illustrate simplification options.
aa 1 8 bb 2 10 cc 3 12 dd 4 13.push @d, @list[0,1,4];or evenpush @d, (split /,/)[0,1,4];open FH, "<:crlf", $fhor running the file throughdos2unixors/\r?\n//;instead ofchomp.