【问题标题】:What causes the warning "Use of uninitialized value" in my program?是什么导致我的程序中出现警告“使用未初始化的值”?
【发布时间】:2011-05-24 06:01:41
【问题描述】:

这对我来说毫无意义。我有这两个子程序。

sub load_config_file {
    if (@_ eq '') {
        die RED . "No configuration file defined" . RESET . "\n";
    } else {
        if (! -e "@_") {
            die RED . "@_ not found!" . RESET . "\n";
        } else {
            if (`cat @_` eq '') {
                die RED . "$config_file_path is an empty file!" . RESET . "\n\n";
            } else {
                print "Configuration file:" . GREEN . "@_" . RESET . "\n";
                my $xml_obj = XML::Simple->new();
                my $config_xml = $xml_obj->XMLin("@_", SuppressEmpty => 1);
                %config_file = %$config_xml;
            }
        }
    }
} # End load_config_file

sub load_guest_os_file {
    if (@_ eq '') {
        die RED . "No guest operating system file defined" . RESET . "\n";
    } else {
        if (! -e "@_") {
            die RED . "@_ not found!" . RESET . "\n";
        } else {
            if (`cat @_` eq '') {
                die RED . "@_ is an empty file!" . RESET . "\n\n";
           } else {
                print "Guest OS file:" . GREEN . "@_" . RESET . "\n";
                my $xml_obj = XML::Simple->new();
                my $guest_os_xml = $xml_obj->XMLin("@_", SuppressEmpty => 1);
                %guest_os_file = %$guest_os_xml;
            }
        }
    }
} # End load_guest_os_file

它们的目的是加载我的脚本所需的特定配置文件。第一个,load_config_file,效果很好。但是当我转到第二个 load_guest_os_file 时,我从 Perl 中得到了这些错误:

Use of uninitialized value $_[0] in join or string at analyze.pl line 146.
Use of uninitialized value $_[0] in join or string at analyze.pl line 148.

我的脚本中的第 146 行是

if (! -e "@_") {

第 148 行是

die RED . "@_ not found!" . RESET . "\n";

我错过了什么?当我这样调用子程序时:

load_config_file($config_file_path)
load_guest_os_file($guest_os_file_path)

…分配给这两个变量的值是

my $config_file_path = './config.xml'

my $guest_os_file_path = './guest_os.xml'

编辑:我还应该添加来自Getopt::Long 处理的命令行参数的两个变量的值。如果没有分配值,则变量只是“声明”,我认为这就是术语。我没有给它赋值,它只是my $config_file_path;my $guest_os_file_path;

更新

这是脚本开头的代码。

#!/usr/bin/perl
use strict;
use warnings;

# Modules to load
use Getopt::Long;
use Term::ANSIColor qw(:constants);
use XML::Simple;
use Net::Ping;
use Net::OpenSSH;
use Data::Dumper;

# Script version
my $version = 'v0.6';

my (%config_file, %guest_os_file, %machines_xml, $ssh_obj);

my @selected_mode;

# Configuration file
my $config_file_path;

# Guest OS file
my $guest_os_file_path;

# Exclusion file
my $exclude_file_path;

# Disables snapshot capture
my $no_snapshots = 0;

my $logfile_path;

my $verbose = 0;

# Program modes
my %program_modes = (
    analyze => \&analyze,
    backup  => \&backup,
    restore  => \&restore,
    help  => \&help,
);

GetOptions(
    'c=s' => \$config_file_path,
    'e=s' => \$exclude_file_path,
    'g=s' => \$guest_os_file_path,
    'l=s' => \$logfile_path,
    'v' => \$verbose,
    'x' => \$no_snapshots,
    'a' => sub { push @selected_mode, "analyze" },
    'b' => sub { push @selected_mode, "backup" },
    'h' => sub { push @selected_mode, "help" },
    'r' => sub { push @selected_mode, "restore" },
    's' => sub { push @selected_mode, "setup" },
);

# Show the help menu if no program mode has been selected
if (@selected_mode == 0) {

    help();

# Throw an error and show the help menu if too many modes are selected
} elsif (@selected_mode > 1) {

    print RED . "Too many program modes specified" . RESET . "\n";

    print "See help menu [-h] for further information\n";

# Run the selected program mode
} elsif (@selected_mode == 1) {

    if ($selected_mode[0] eq 'help') {

        help();

    } else {

        # Die unless user is root
        die RED . "You must be have superuser permissions to run this script" . RESET . "\n" unless ($> == 0);

        system "clear";

        print "Solignis's VMware $selected_mode[0] script $version for ESX\\ESX(i) 4.0+\n";

        load_config_file($config_file_path);

        if ($selected_mode[0] eq 'analyze') {

            load_guest_os_file($guest_os_file_path);

        } else {

            ######

        }

    }

}

【问题讨论】:

  • 那么是什么导致了警告?是我在下面猜到的吗?

标签: perl


【解决方案1】:

这将永远是错误的:

if (@_ eq '') {

当为空时,数组在标量上下文中给出 0,而不是 ''。 只是:

if ( ! @_ ) {

足以测试是否没有通过。

但我认为您实际上是要确保传递了定义的值:

if ( ! defined $_[0] ) {

要知道为什么它 $_[0] 是未定义的,我们必须查看从声明到传递给子的代码。

【讨论】:

  • 我会从脚本的开头发布声明
【解决方案2】:

您的代码上的一些通用指针:

  • 考虑使用 elsif 而不是一直嵌套的 else 块。
  • 如果您要过滤掉一堆错误条件,请考虑使用语句修饰符 if/unless 逻辑。
  • 考虑使用-z-s 来获取文件大小(请参阅http://perldoc.perl.org/functions/-X.html)。
  • 在您的子例程顶部解压缩@_
  • 尽量减少使用全局变量。明确地将所有数据传入和传出您的潜艇。

这是你的第一个子的清理版本:

sub load_config_file {
    my $config_file = shift;

    die RED . "No configuration file defined" . RESET . "\n"
        unless defined $config_file;

    die RED . "$config_file not found!" . RESET . "\n"
        unless -e $config_file;

    die RED . "$config_file_path is an empty file!" . RESET . "\n\n"
        if -z $config_file;


    print "Configuration file:" . GREEN . "@_" . RESET . "\n";

    my $xml_obj = XML::Simple->new();
    my $config_xml = $xml_obj->XMLin("@_", SuppressEmpty => 1);

    return $config_xml;

} # End load_config_file

顺便说一句,我不确定您在 die 消息中使用 REDs 和 RESETs 是怎么回事,但我觉得使用异常处理程序可以更好地实现。

【讨论】:

  • 非常好,-z的使用是我一直在寻找的。​​span>
【解决方案3】:

如果您只使用一个值的 subs,您不妨将其复制到一个变量中,而不是使用 @_,如下所示:

sub load_guest_os_file {
    my $path = shift;

您正在执行的测试可以做得更好,并且它们不需要在彼此内部,因为唯一的结果是die

$path    || die RED . "No guest operating system file defined" . RESET . "\n";
-e $path || die RED . "$path not found!" . RESET . "\n";
-s $path || die RED . "$path is an empty file!" . RESET . "\n\n";

-e 检查在功能上不是必需的,因为如果文件丢失,-s 也会失败。不过,它会给出更好的错误。

另外,如果您在函数中使用参数,则不使用 sub 操作全局变量可能更一致,而是提供返回值,例如:

    ...
    return %$config_xml;
}

%config_file = load_config_file($config_file_path);

【讨论】:

  • 是的,我按照你的建议做了,我很喜欢。
【解决方案4】:

为了得到上面提到的警告,子程序load_guest_os_file的第一个参数必须是未定义的(这是声明后的默认值)。

从您显示的源代码中,我可以看到这种情况发生的唯一可能性是没有给出有效的选项-g<path>,因此变量$guest_os_file_path 永远不会被赋值。然后子程序load_guest_os_file 将被调用,并使用未定义的值作为其参数,如下所示

load_guest_os_file(undef)

Perl 会给出这些警告。

【讨论】:

    猜你喜欢
    • 2011-01-16
    • 2016-03-03
    • 1970-01-01
    • 2021-03-10
    • 2019-08-28
    • 2011-10-19
    • 1970-01-01
    • 2023-04-11
    • 1970-01-01
    相关资源
    最近更新 更多