Question

i have a problem. This perl program should open all files and map them together, something similiar to paste command in unix system.

my @files;
for (@fileList ? @fileList : qw(-)) {
open  $files[@files], '<', $_; #}
}
while (grep defined, (my @lines = map {scalar <$_>;} @files)) {
    chomp @lines;
    print join("\t", @lines), "\n";
}

The problem is that, when it comes to two different files like

One 
Two 
Three

And:

Apple
Banana
Orange
Kiwi

It throws me an error of uninitialized value.

Use of uninitialized value $lines[0] in chomp 
Use of uninitialized value $lines[0] in join 

Also same error vice versa, when files are Apple,Banana.. and One two three.

Thank you in advance

Was it helpful?

Solution

The problem is that since your files have a different length, you will get some undefined values in your @lines array. You cannot filter them out in the while condition, but you can filter them out afterwards, inside the loop:

while (grep defined, (my @lines = map {scalar <$_>;} @files)) {
    @lines = map defined($_) ? $_ : "", @lines;

This will replace undefined values with the empty string, removing any uninitialized warnings for those values, while keeping your tabs correctly aligned.

Note that your code actually does what it is meant to do, because undef will stringify to the empty string. It is only because you have warnings on that you get the warnings about it. However, it is a very good idea to have warnings on, so errors such as this can be found and fixed properly.

You should note that using open without checking its return value is not a good idea, unless you explicitly handle the failed cases. The proper way is to do this:

open $files[@files], '<', $_ or die $!;

For simplicity one can also use

use autodie;

The autodie module will produce fatal errors for critical function calls such as open.

OTHER TIPS

If you have Perl v5.10 or later installed (and you really should, as it is five years old now) then you can use the // (defined-or) operator to substitute a null string for undef after the end of the files. It will also impose scalar context on its operands, so there is no need to use the scalar operator. In addition you must substitute the length operator for defined, resulting in this code

while (grep length, (my @lines = map { <$_> // '' } @files)) {
    chomp @lines;
    print join("\t", @lines), "\n";
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top