This is a test version of Biostars. For the public version, visit https://www.biostars.org.
Why my subroutine show an empty output file using a regex pattern?

Have been scratching my head for a few hours on this, seems like a silly issue, but just can't find a solution. I'm trying to execute a Perl script using regex for pattern search, but the subroutine that i write, results in an empty file without results. I suppose the array can be the problem, i would really appreciate you help, I don't have much experience on this.

I'm open and read the <FASTA.file> with $ARGV and then declare the output file:

open (R, "$ARGV[0]");
open E, ">output.file";

Example of regex:

my $mot =~ m/*^[MNC.RL.]*/gi;

and then send it the sequences and patterns in an subroutine:

my $v2 = &v1($seq,$mot);
sub v1{
    my $seq = $_[0];
    my $mot = $_[1];
    my $motif = '';

    open E, ">./output.fasta";
    if ($seq= ~ m/$mot/gi){
        print E qq($seq\n); 
        }#fi

           else {
           $motif.=$v2;
           }#else

        close(E);
        return ($v1);

    }

The output file is empty, i really don't known why. If you can help me find the error or more options for this, that would be cool.

This is a reproducible example, which practically does the same, search a pattern (regex), but the output file is empty or it isn't that i expected:

#!/usr/bin/env perl

open (R, "$ARGV[0]");
open E, ">./output.fasta";
open C, ">./tmp.txt";

my $head ='';
my $flag =0;
my $seq ='';
my $list ='';
my $mot =~ "m/*^[MNC.RL.]*/gi";

while (my $line = <R>){
    chomp($line);
    if ($line=~ m/>/ and $flag ==0) {
        $head= $line;
    }#fi

    elsif ($line=~ m/>/ and $flag >=1) {
        print E qq ($head\t$seq\n);
        my $v2 = &v1($seq,$mot);

         $list.=$v2."\n";
         $flag= 0;
         $head= $line;
         $seq='';
    }#elsif 

        else {
                $seq.=$line."";
                $flag++;
        }#else


}#while
my $v2 = &v1($seq,$mot);
$list.=$v2."\n";
print E qq ($head\n$seq\n);
print C qq ($list\n);

##########
sub v1{
    my $seq = $_[0];
    my $mot = $_[1];
    my $motif = '';

    open E, ">./output.fasta";
    if ($seq=~ m/$mot/gi){
        print E qq($seq\n);
        }#fi
        else {
        $list.=$v2;
        }#else


        close(E);
        return ($v1);

    }

Thanks in advance!

perl subroutine regex

1 answer

Before getting to the core of the question, I would suggest using lexical filehandles (variables declared using my), and the "three argument" version of the open function (see the Simple Examples section on the Perl documentation for open). This would change your open statements to:

open my $R, "<", "$ARGV[0]");
open my $E, ">", "./output.fasta";
open my $C, ">", "./tmp.txt";

and the while statement where you read from $R to:

while (my $line = <$R>){

What you are using are called "bareword filehandles" which are global, and have been deprecated in recent versions of Perl.

Back to your issue: are you meaning to store the regex in $mot? If so, the line

my $mot =~ "m/*^[MNC.RL.]*/gi";

does not do this. I believe that line will declare an (empty) variable $mot and then search it for the patern "*^[MNC.RL.]*" which will of course fail. You could either initialize $mot with the pattern using the qr() operator, which will store the string you give it as a regular expression into the variable:

my $mot =~ qr/*^[MNC.RL.]*/;

Now you can use it later in your V1 sub:

if ($seq =~ /$mot/gi) { # m is implied if "/" is the delimiter

Or, since it seems like you might not need to ever change the pattern you give that function, just remove it as a parameter to V1 and hard code it:

if ($seq=~ /*^[MNC.RL.]*/gi) {

Another issue, going back to your use of global file handles, you're opening the same file handle again in the V1 function. Delete your first open E statement at the start of the script and change the V1 script to look more like this (Edit: I changed ">" to ">>" since that will append to the file; the former will truncate the file each time):

open my $E, ">>", "./output.fasta";
# ...
print $E "$seq\n"; # Shouldn't need qq here
# ...
close $E;

Log in to answer this question.