Diamond operator in Until Statement (perl)

Hello:
I have the following perl script which is giving me trouble inside the second elsif statement. The purpose of the script is to go through a file and print out only those lines which contain pertinent information. The tricky part came when I realized that certain items actually spanned two or three lines. (For example, "FUNCTION:" information in the sample file).

The elsif condition is intended to recognize the beginning of the desired information (which it does) and the until condition is intended to recognize the end of the desired information. Strangely, the script appears to loop through the until construct the appropriate number of times, but it prints the initial line every time instead of the successive line. I suspect I'm using the diamond operator incorrectly.

Here is a sample of the file. :

ID   MYPR_HUMAN              Reviewed;         277 AA.
AC   P60201; P04400; P06905; Q502Y1;
DT   01-JAN-1988, integrated into UniProtKB/Swiss-Prot.
DT   23-JAN-2007, sequence version 2.
DT   25-NOV-2008, entry version 62.
DE   RecName: Full=Myelin proteolipid protein;
DE            Short=PLP;
DE   AltName: Full=Lipophilin;
GN   Name=PLP1; Synonyms=PLP;
OS   Homo sapiens (Human).
CC   -!- FUNCTION: Involved in the transport of proteins between the
CC       endosomes and the trans Golgi network (By similarity).
CC   -!- SUBCELLULAR LOCATION: Cell membrane; Lipid-anchor; Cytoplasmic
CC       side (Potential).
CC   -!- TISSUE SPECIFICITY: Ubiquitous.
CC   -!- SIMILARITY: Belongs to the small GTPase superfamily. Rab family.
#!/usr/local/bin/perl

use strict;

my @files;
my $file;
my $IN;

# Create array of files in current directory
my @files = `ls Batch*`;

foreach $file (@files) {
    open ($IN, $file) or die $!;
    my $i = 0;
    while (<$IN>) {
        if (/^(ID   )([A-Za-z0-9_]*)/) {
            print "GENE: $2\n";
        }
        elsif (/(DE   RecName: Full=)(.*);/) {
            print "NAME: $2\n";
        } 
        elsif ((/^(CC   -!- )(FUNCTION:.*)/) || (/(CC   -!- )(TISSUE SPECIFICITY:.*)/)) {
            print $2;
            until (<$IN> =~ /(-!-)/) {
                print $_;
            }
            print "\n";
        }
    }
    close $IN;
}

For what it's worth, I can get it working perfectly using the code below inside the elsif. I'm just curious why my initial attempt is failing. (Note: This second example has a regEx inside the until construct, but that shouldn't make the difference).

            print $2;
            my $nxtLine = <$IN>;
            until ($nxtLine =~ /(-!-)/) {
                $nxtLine =~ /CC *(.*)/;
                print $1;
                $nxtLine = <$IN>;

Well, I think I figured it out. Essentially, the diamond operator just grabs the next line of input and assigns it to $_, but the diamond operator is not itself the input. I was treating it like a line of input.
Nevertheless, any criticism or critiques on my code or suggestions for alternate methods is certainly still welcome.

Another approach:

perl -ne'BEGIN { $Sep = "=" x 65 }
  /^ID   (\w+)/ and $Gene = $1;
  /^DE   RecName: Full=([^;]*)/ and $Name = $1;
  if (/^CC   -!- FUNCTION:/../CC   -!- SUBCELLULAR/) {
    $Func .= $1."\n   " if 
	  !/SUBCELLULAR/ && (/(FUNCTION:.*)/ || /CC(.*)/)
	}
  if (/^CC   -!- TISSUE SPECIFICITY:/../^CC   -!- SIMILARITY:/) {
    $Spec .= $1."\n   " if 
	  !/CC   -!- SIMILARITY:/ && (/(TISSUE SPECIFICITY:.*)/ || /CC(.*)/)
	}
  printf "$Sep\n\nGENE: %s\n\nNAME: %s\n\n%s\n%s\n\n", $Gene, $Name, 
    $Func, $Spec and ($Func, $Spec) = undef if eof
  '  Batch*

radoulov: Thanks for the reply. I can tell you spent some time on that.
Unfortunately, I'm pretty new to perl and I've never used the command line option (which I think that is), so it might take me a while to decipher what's going on.

If you don't mind, I have a couple questions to start with:

1) How does this line of code work:

/^ID   (\w+)/ and $Gene = $1;

I think it's saying: if the regEx finds a match, assign what's in the parenthesis to $Gene.

If that's it, it's very similar to what I was doing here:

if (/^(ID   )([A-Za-z0-9_]*)/) {
            print "GENE: $2\n";
        }

I just don't understand how you are able to do make a conditional statement without an 'if ' construct. Can you please elaborate on how this works?

2)My second question is about this line:

if (/^CC   -!- FUNCTION:/../CC   -!- SUBCELLULAR/) {

It seems like this regEx contains four slashes. I've never seen one like that. I assume this is used to get the text in between FUNCTION and SUBCELLULAR, but again, I just don't understand how it works.

Thanks again for your reply, and thanks in advance for your help with these questions. I know that I'm going to learn a lot from this exercise and I can tell that your approach is very efficient.

Sure.
The && and || (and and and or) are also called "Short Circuit" operators.
From Perl Idioms Explained - && and || "Short Circuit" operators (actually the Camel Book):

So only if the fisrt expression returns true (i.e. if there is a match)
evaluate the second one (i.e. set $Gene to $1).

Right, it's simply the range .. operator:

$ print '
junk
start
yes
yes
end
junk
'|perl -ne'print if/start/../end/'
start
yes
yes
end

(see perldoc perlop | less -p'range operator' for more).

Back to your original question (which you think you solved)...

First, I recommend against using a $ inside a file descriptor ($IN). This makes it look like something is happening that isn't: namely, file descriptors ARE NOT SCALAR VARIABLES in Perl. They are a class of variables in their own right. What's really happening is, I think, $IN is evaluating into undef, so that you have:

 while (<>) { 
...
 my $nxtLine = <>;

and so on.

As you noted, the <> is an operator that reads a line from the filedescriptor in between the brackets, or if none given, from the next command given on the command line, or if none are present, from STDIN (standard input, that is, piped or redirected input).

So $IN I think is going to make things confusing. Just use "IN" here.

Or, better yet,use the command line and the aforementioned feature:

  $ your_perl_script.pl Batch*

And in your code:

while (<>) { 
...
 my $nxtLine = <>;
...