Perl - "Use of uninitialized value" 应该设置值时出错?

Perl - "Use of uninitialized value" error when value should be set?

我在嵌套 "while" 循环中读取文件时遇到 "Use of uninitialized value" 错误。我已将我的代码减少到最低限度并删除了 filenames/directories 以保护隐私:

#/usr/bin/perl -w
use strict;
use warnings;
use diagnostics;

my $line_gene = undef;
my $gene_name = undef;
my $gene_chr  = undef;
my $gene_pos  = undef;
my $line_pval = undef;
my $chr       = undef;
my $pos_start = undef;
my $pos_end   = undef;
my $pos_mid   = undef;
my $pval      = undef;

open(IN_GENE,"somefile_gene") || die "Failed, gene\n";
open(IN_PVAL,"somefile_pval") || die "Failed, pval\n";

while ($line_gene = <IN_GENE>) {
   chomp $line_gene;
   ($gene_name,$gene_chr,$gene_pos) = split(/\t/,$line_gene);
   while ($line_pval = <IN_PVAL>) {
      chomp $line_pval;
      ($chr,$pos_start,$pos_end,undef,undef,$pval) = split(/\t/,$line_pval);
      $pos_mid = ($pos_start + $pos_end)/2;
      if ($gene_chr == $chr) {
         print $gene_chr."\t".$chr."\n";
      }

   }
   seek IN_PVAL, 0, 0;
}
exit;

当我 运行 此代码时,我收到以下错误消息:

Use of uninitialized value $gene_chr in numeric eq (==) at Xtest.pl line 36,
<IN_PVAL> line 5772 (#1)

然后在这些 "Use of uninitialized value" 警告之后是打印到标准输入的正确行:

6       6
1       1
20      20
...     ...

除非我明显做错了什么,否则我不明白为什么它认为 $gene_chr 未初始化。同样有趣的是,对于输入文件 <IN_PVAL> 的每一行,它都会从第 1 行到第 5772 行打印上面的 "Use of uninitialized value" 警告(见上面的警告),除了这个文件只有 2886 行,正好5772的一半.

输入文件(<IN_GENE><IN_PVAL>)都没有空行,无论是在中间还是在末尾,并且都按预期格式设置了正确的字段数,none 其中为空。

如有任何建议,我们将不胜感激。谢谢!

"chr" 是保留关键字。你不应该使用它作为变量名,不管它是否有效。

您应该在拆分后添加一行 print Dumper($gene_chr,$chr,$line_pval);,并在顶部添加 use Data::Dumper;。它会告诉你很多关于你的数据的信息。我想问题可能出在您的数据文件中。

也许还可以在某处添加 exit if $. > 10 以在从文件中读取 10 行后退出并使调试更容易。

如果 $gene_chr 未定义,则这意味着,对于 somefile_gene 的一行或多行,

($gene_name,$gene_chr,$gene_pos) = split(/\t/,$line_gene);

正在返回 undef 作为它的第二个值(或者返回少于两个值,这实际上是一回事)。

我能想到这可能发生的两种方式:

1) 这些行不包含制表符,导致整个未拆分的行被放入 $gene_name。这可能是由于某行错误地使用空格而不是制表符来分隔字段。

2) 在第一个值之后,该行包含两个连续的制表符。如果 $gene_name 的长度变化很大,那么这可能是由于有人试图让字段排列更多 "nicely" 以进行视觉呈现。

What's also interesting is that for every line of the input file , it prints the above "Use of uninitialized value" warning from line 1 to line 5772 (see above warning), except that this file only has 2886 lines, exactly half of 5772.

它显示的行号只是从文件中读取了多少行的计数器。由于您 seek 每次都回到文件的开头而不是关闭并重新打开它,因此计数器永远不会重置。

从 1 到(2 * pval 文件中的行数)的行号表明 pval 文件中的错误在前两行,即 1..2886 和 2887..分别为 5772。如果错误出现在文件的后面,计数器会更高。

此外,作为一般提示,除非 pval 文件中的行非常长,否则我会认真考虑是否可以将其内容一次读入键入 $pval_chr 的哈希中然后用

替换整个内部循环
if (exists $pval_hash{$gene_chr}) { ... do stuff ... }

如果基因文件中有几行以上,这将显着提高性能,因为它不需要为基因文件中的每一行重新读取 pval 文件。

由于我没有太多要说的,所以这主要是有根据的猜测。但是,有了一些反馈,我认为我们可以有所作为。我添加了这个作为答案,因为我觉得评论的信息太多了。

分析

显然在某些时候,拆分中没有足够的字段来为 $gene_chr 赋值。这就是它变得未初始化的原因。就是这一行:

($gene_name,$gene_chr,$gene_pos) = split(/\t/,$line_gene);

如果该行中根本没有制表符,就会发生这种情况,否则您会得到一个空字符串,并且您的错误将是 ""== 中不是数字。即:

Argument "" isn't numeric in numeric eq (==)

由于您的错误报告行是内部循环文件中最大行数的两倍,因此我推测您的 IN_GENE 文件只有两行数据。此外,我猜它有一个尾随的 blank 行,您没有注意到,这就是导致错误的原因。它并没有完全加起来,但值得一试,看看它是否能解决您的问题。

解决方案

尝试添加检查以查看是否有空行。类似于:

...
while ($line_gene = <IN_GENE>) {
   chomp $line_gene;
   unless ($line_gene =~ /\S/) {   # unless the line contains non-whitespace
       warn "Warning: Blank line in gene file";
       next;
   }

这将警告您空行,并跳过它们。警告(以及其他错误)转到 STDERR,这意味着您可以将它们与 STDOUT 中的标准输出分开。