Что вызывает предупреждение «Использование неинициализированного значения» в моей программе? - PullRequest
1 голос
/ 23 мая 2011

Это не имеет никакого смысла для меня.У меня есть эти две подпрограммы.

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 {

            ######

        }

    }

}

Ответы [ 4 ]

10 голосов
/ 23 мая 2011

Это всегда будет ложно:

if (@_ eq '') {

Когда пусто, массив дает 0 в скалярном контексте, а не ''.Просто:

if ( ! @_ ) {

достаточно для проверки, если ничего не было передано.

Но я думаю, что вы действительно хотите убедиться, что определенное значение было передано:

if ( ! defined $_[0] ) {

Чтобы узнать, почему он $_[0] не определен, нам нужно увидеть код из объявления, куда он передается в подпрограмму.

3 голосов
/ 23 мая 2011

Некоторые общие указатели на ваш код:

  • Попробуйте использовать elsif вместо постоянно вложенных блоков else.
  • Если у вас есть куча состояний ошибок, которые вы отфильтровываете, рассмотрите возможность использования модификатора оператора, если / если логика.
  • Попробуйте использовать -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

Кстати, я не уверен, что у вас происходит с RED s и RESET s в ваших сообщениях кубика, но у меня есть ощущение, что это может быть лучше достигнуто с помощью обработчика исключений.

2 голосов
/ 23 мая 2011

Если вы используете подпрограммы только с одним значением, вы можете также скопировать это значение в переменную вместо использования @_, например, так:

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 завершится неудачей также, еслифайл отсутствует.Однако это даст лучшую ошибку.

Кроме того, если вы используете аргументы для своей функции, может быть более последовательным не манипулировать глобальными переменными с помощью подпрограммы, а вместо этого давать возвращаемое значение, такое как:

    ...
    return %$config_xml;
}

%config_file = load_config_file($config_file_path);
0 голосов
/ 24 мая 2011

Чтобы получить предупреждения, упомянутые выше, первый параметр подпрограммы load_guest_os_file должен быть неопределенным (это значение по умолчанию после объявления).

Из исходного кода, который вы показали, единственная возможность, которую я вижу для этого сценария, состоит в том, что не была предоставлена ​​допустимая опция -g<path>, и поэтому переменной $guest_os_file_path никогда не присваивается значение. Тогда подпрограмма load_guest_os_file будет вызываться с неопределенным значением в качестве параметра, подобного этому

load_guest_os_file(undef)

и Perl выдаст эти предупреждения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...