Search code examples
perlwhile-loopscalar-context

After successfully using grep on a variable it prints blank


I am opening a directory that has files that look like the following. Here is one file:

    >UVWXY
    ABCDEFGHIJKLMNOPQRSTUVWXYZ
    >STUVW
    ABCDEFGHIJKLMNOPQRSTUVWXYZ
    >QRSTU
    ABCDEFGHIJKLMNOPQRSTUVWXYZ 

Here is a second file:

   >EFGHI
   ABCDEFGHIJKLMNOPQRSTUVWXYZ 

Here is my code:

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

   my ($directory) = @ARGV;
   my $dir = "$directory";
   my @ArrayofFiles = glob "$dir/*";

   open(OUT, ">", "/path/to/output.txt") or die $!;

   foreach my $file(@ArrayofFiles){
          open(my $fastas, $file) or die $!;
          my $numberoffastas = grep{/>/}<$fastas>;
          #print $numberoffastas, "\n"; 
          while (my $line = <$fastas>){
                 print $line, "\n";
          }
    }

Nothing is printed out for $line, but this code correctly counts the number of ">"s that appear in the file when it is opened, evidenced by printing $numberoffastas.
How can I fix this code so that $line = something like:

     >EFGHI 

or

    ABCDEFGHIJKLMNOPQRSTUVWXYZ  

Thanks


Solution

  • my $numberoffastas = grep{/>/}<$fastas>;
    

    calls readline on the $fastas filehandle in list context, which consumes all the input on the filehandle. At your subsequent call in while (my $line = <$fastas>), there is no more input on that filehandle to provide, and the while condition fails.

    Save the inputs in an array and perform both operations on the array

    my @inp = <$fastas>;
    my $numberoffastas = grep {/>/} @inp;
    ...
    foreach my $line (@inp) {
       ...
    }
    

    or if you are worried that the files are too large and will give you memory headaches, reopen the file

    my $numberoffastas = grep {/>/} <$fastas>;
    close $fastas;
    open $fastas, $file;
    ...
    while (my $line = <$fastas>) { ... }
    

    or seek to the beginning of the file

    open my $fastas, '+<', $file;    #   +<  means random-access mode
    my $numberoffastas = grep {/>/} <$fastas>;
    ...
    seek $fastas, 0, 0;              #   rewind to beginning of file
    while (my $line = <$fastas>) { ... }