title: perl do something once in a while loop
body: <p>I am frequently working with biological sequence data (FASTAs) that have the following format, where a leading left angle bracket is used as a delimiter to indicate a new sequence header. These files often have text wrapping (except for the headers):</p>
  
  <pre><code>&gt;header1
  ACTGACTGACTGACTG
  ACTGACTGACTGACTG
  &gt;header2
  CTGGGACTAGGGGGAG
  CTGGGACTAGGGGGAG
  </code></pre>
  
  <p>Often, I want to avoid reading the entire file into memory because it can be many MBs (sometimes GBs), so I try to focus on while loops and reading line by line. However, I find myself often needing to add extra code to do something unique at the top or bottom of the file. For instance, today I wanted to remove the text wrapping of some file, which seemed as simple as:</p>
  
  <pre><code>while (my $line = &lt;$inputfasta_fh&gt;) {
      chomp($line);
      if ($line =~ /^&gt;/) {
          print $outputfasta_fh "$line\n";
      }
      else {
          print $outputfasta_fh $line;
      }
  }
  </code></pre>
  
  <p>But, I realized I need a newline before all the headers except the first one (otherwise they would be concatenated to end of the the previous sequence). So, this is my crude work-around.</p>
  
  <pre><code>my $switch = 0;
  while (my $line = &lt;$inputfasta_fh&gt;) {
      chomp($line);
      if ($line =~ /^&gt;/) {
          if ($switch == 1) {
              print $outputfasta_fh "\n";
          }
          print $outputfasta_fh "$line\n";
          $switch = 1;
      }
      else {
          print $outputfasta_fh $line;
      }
  }
  </code></pre>
  
  <p>Previously, I've had other issues where I need to do something with the last line. For example, I had a script that would read a fasta, store each header and then start counting its sequence length (again line-by-line), and if it was within a range I specified, I saved it to another file. The counting would abort if the length went past the maximum, but I wouldn't know if it was more than the minimum until I reached another header or the end of the file. In the latter case, I had to repeat the length-checking subroutine below the while loop. I would like to avoid repeating that last part.</p>
  
  <pre><code>my $length = 0;
  my $header;
  my @line_array;
  
  while (my $line = &lt;$inputfasta_fh&gt;) {
      chomp($line);
      if ($line =~ /^&gt;/) {
          # check if previous sequence had a length within range
          if (check_length($length, $minlength, $maxlength) == 1) {
              print $outputfasta_fh "$header\n";
              print $outputfasta_fh join ("\n", @line_array), "\n";
          }
          undef @line_array;
          $header = $line;
          $length = 0;
      }
      else {
          if ($length &lt;= $maxlength) { # no point in measuring any more
              push (@linearray, $line);
              $length += length($line);
          }
      }
  }
  
  #and now for the last sequence
  if (check_length($length, $minlength, $maxlength) == 1) {
      print $outputfasta_fh "$header\n";
      print $outputfasta_fh join ("\n", @line_array), "\n";
  }
  
  sub check_length {
      my ($length, $minlength, $maxlength) = @_;
      if (($length &gt;= $minlength) &amp;&amp; ($length &lt;= $maxlength)) {
          return 1;
      }
      else {
          return 0;
      }
  }
  </code></pre>
  
  <p>So, my basic question is how to indicate I want to do something once in a loop without resorting to counters or repeating code outside the loop? Thanks for any help!</p>