Jack Jack - 1 month ago 7
Perl Question

Can't call method "print" on an undefined value

Can't call method print on an undefined value in line 40 line 2.

Here is the code. I use FileHandle to settle files:

#!/usr/bin/perl
use strict;
use warnings;
use FileHandle;

die unless (@ARGV ==4|| @ARGV ==5);

my @input =();
$input[0]=$ARGV[3];
$input[1]=$ARGV[4] if ($#ARGV==4);
chomp @input;
$input[0] =~ /([^\/]+)$/;
my $out = "$1.insert";
my $lane= "$1";

my %fh=();
open (Info,">$ARGV[1]") || die "$!";
open (AA,"<$ARGV[0]") || die "$!";

while(<AA>){
chomp;
my @inf=split;
my $iden=$inf[0];
my $outputfile="$ARGV[2]/$iden";
$fh{$iden}=FileHandle->new(">$outputfile");
}
close AA;

foreach my $input (@input) {
open (IN, "<$input" ) or die "$!" ;
my @path=split (/\//,$input);
print Info "#$path[-1]\n";
while (<IN>) {
my $line1 = $_;
my ($id1,$iden1) = (split "\t", $line1)[6,7];
my $line2 = <IN> ;
my ($id2,$iden2) = (split "\t", $line2)[6,7];
if ($id1 eq '+' && $id2 eq '-') {
my @inf=split(/\t/,$line1);
$fh{$iden1}->print($line1);
$fh{$iden2}->print($line2);
}
}
close IN;
}


I’ve tried multiple variations of this, but none of them seem to work. Any ideas?

Answer

Please remember that the primary worth of a Stack Overflow post is not to fix your particular problem, but to help the thousands of others who may be stuck in the same way. With that in mind, "I fixed it, thanks, bye" is more than a little selfish

As I said in my comment, using open directly on a hash element is much preferable to involving FileHandle. Perl will autovivify the hash element and create a file handle for you, and most people at all familiar with Perl will thank you for not making them read up again on the FileHandle documentation

I rewrote your code like this, which is much more Perlish and relies less on "magic numbers" to access @ARGV. You should really assign @ARGV to a list of named scalars, or - better still - use Getopt::Long so that they are named anyway

You should open your file handles as late as possible, and close the output handles early

There is no need to chomp the contents of @ARGVunless you could be be called under strange and errant circumstances, in which case you need to do a hell of a lot more to verify the input

You never use the result of $input[0] =~ /([^\/]+)$/ or the variables $out and $lane, so I removed them

#!/usr/bin/perl

use strict;
use warnings 'all';

# $ARGV[0] -- input file
# $ARGV[1] -- output log file
# $ARGV[2] -- directory for outputs per ident
# $ARGV[3] -- 1, $input[0]
# $ARGV[4] -- 2, $input[1] or undef

die "Fix the parameters" unless @ARGV == 4 or @ARGV == 5;

my @input = @ARGV[3,4];

my %fh;

{
    open my $fh, '<', $ARGV[0] or die $!;

    while ( <$fh> ) {
        my $id         = ( split )[0];
        my $outputfile = "$ARGV[2]/$id";
        open $fh{$id}, '>', $outputfile or die qq{Unable to open "$outputfile" for output: $!};
    }
}

open my $log_fh, '>', $ARGV[1] or die qq{Unable to open ""};

for my $input ( @input ) {

    next unless $input # skip unspecified parameters

    my @path = split qr|/|, $input;   # Really should be done by File::Spec
    print $log_fh "#$path[-1]\n";     # Or File::Basename

    open my $fh, '<', $input or die qq{Unable to open "$input" for input: $!};

    while ( my $line0 = <$fh> ) {

        chomp $line0;

        my $line1 = <$fh>;
        chomp $line1;

        my ($id0, $iden0) = (split /\t/, $line0)[6,7];
        my ($id1, $iden1) = (split /\t/, $line1)[6,7];

        if ( $id0 eq '+' and $id1 eq '-' ) {

            for ($iden0, $iden1) {
                die qq{No output file for "$_"} unless $fh{$_};
                print $fh{$_} $line0;
            }
        }
    }
}

close for values %fh;