运行以下核心代码有警告信息:
Use of uninitialized value $_ in pattern match (m//) at test.pl line 25.
Use of uninitialized value $_ in pattern match (m//) at test.pl line 29.
以为是输入文件中没有 ^Ref_ann\s+ 和 ^Symbol 的行,但测试又可以正确打印 $gff 和 $id_name。
其实本来不想纠结这个问题的,既然程序可以得到自己想要的,为什么要纠结这种小细节?当然也可以用另外一种写法去避免这种问题。可是今天心情不好,特别焦躁,作为一个隐藏极深的处女座,实在过不去这个坎儿。
省略纠结的探索过程,直接说明问题所在:
关键词是$_,$_是Perl中最常用的特殊变量,包含了和模式匹配内容。当匹配到^Ref_seq时,$_是输入$cfg文件中Ref_seq对应的行,但是在正确匹配之后又有一步操作就是打开一个$fa文件,也就是有了一个新的输入,此时$_就变成了$fa中的内容。测试16行可以打印FA文件的最后一行,但是测试17行会有如下报错:
Use of uninitialized value $_ in concatenation (.) or string at test.pl line 测试17, <FA> line 8.
这是因为当读取FA文件完毕后,$_会清空,变成未定义。
此时再去匹配^Ref_ann和^Symbol就会提示未初始化的值。
之所以能后正确输出$gff和$id_name是因为下一个文件句柄<CFG>不会再匹配到^Ref_seq,因此不会再重新输入一个文件了。
输入\$cfg文件是这样的:
Ref_seq input.fa
Ref_ann input.gff3
Symbol input.list
input.fa文件格式是这样的:
>1
AAAAAAAAAAA
CCCCCCCCCC
GGGGG
>2
TTTTTTTTTTTTT
AAAAAAAAAAAA
CCCCCC
核心代码段:
1 open(CFG,"$cfg")||die $!;
2 while(<CFG>){
3 chomp;next if(/^#/);
4 if(/^Ref_seq/){
5 $fa=(split /\s+/,$_)[1];$fa=abs_path($fa);
6 $genome=basename($fa);
7 if(!-f "$odir/$genome"){
8 open(FA,"$fa")||die $!;
9 open(GE,">$odir/$genome")||die $!;
10 while(<FA>){
11 chomp;
12 if(/>(.+)/){
13 $chr=">chr".(split /\s+/,$1)[0];
14 }else{
15 $seq{$chr}.=$_;
16 }
测试16 print "$_\n";
17 }
测试17 print "$_\n";
18 foreach my $chr_seq(sort keys %seq){
19 print GE $chr_seq,"\n",$seq{$chr_seq},"\n";
20 }
21 close(GE);
22 close(FA);
23 }
24 }
25 if(/^Ref_ann\s+/){
26 $gff=(split /\s+/,$_)[1];$gff=abs_path($gff);
27 print "$gff\n";
28 }
29 if(/^Symbol/){
30 $id_name=(split /\s+/,$_)[1];$id_name=abs_path($id_name);
31 print "$id_name\n";
32 }
33 }
34 close(CFG);
强调一个重点单词是"输入",没有输入就没有$_,除非自己先定义$_。例如:
#!/usr/bin/perl -w
my $a=1;
print "$_\n";
会报错:Use of uninitialized value $_ in print at b.pl line 3.
$_="good";
print "$_\n";
不会报错。
my @a = ("good","luck");
foreach (@a){
print "$_\n";
}
不会报错。