Search code examples
perlvariablesglobal-variablestemp

The difference between `$/` and `local $/`


For my program, I need to use FASTA files and do some calculations with them. In order to do that, I used local $/ = "^>, to chomp up my file in to header line and sequence lines. While my program does what I want it to do, why can't I just simply use $/ = "^>"? When I tried it, my results were not what I needed, I'm interested why is that so. Here's my simplified code:

my @array;
while(<>){
    local $/ = "^>";
    chomp;
    push (@array, $_);
    if(eof){
        for(@array){
            ...
        }
    ...
    }
    if(eof){
        @array = ();
    }

Solution

  • local $var saves the value of $var, and adds a directive to the stack that will cause the value of $var to be restored when the scope is exited (even by exception). It's the closest thing to my that's available to package variables.

    $_ = 123;
    {
       local $_ = 456;
       # $_ is 456 here.
    }
    # $_ is back to being 123 here.
    

    This is useful to avoid causing problems in surrounding code or in the caller (in the case of subs).

    Note that value of $/ is matched character-for-character. It's not treated as a regular expression.

    Note that $/ appears to be set for no reason in the code you posted (unless you left something out).


    why can't I just simply use $/ = "^>"

    Then, the change wouldn't be undone at the end of the block, so it would affect the <> in the while condition as well as any code after your loop that performs reads.


    How I'd handle a FASTA file:

    my ($header, $seq);
    while (1) {
       my $line = <>;
       if (!defined($line) || $line =~ /^>/) {
          work($header, $seq) if defined($header);
    
          last if !defined($line);
    
          chomp($line);
          $header = substr($line, 1);
          $seq = "";
       } else {
          chomp($line);
          $seq .= $line;
       }
    }