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 中的标准输出分开。
我在嵌套 "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 中的标准输出分开。