Как я могу перезапустить цикл «do-while» после выхода из цикла foreach? - PullRequest
4 голосов
/ 22 декабря 2011

У меня есть небольшой фрагмент кода из моего скрипта конфигурации, идея заключается в том, что конфигурация загружается, после чего каждый ключ проверяется на введенное имя хоста. Но если обнаружено, что конфигурация содержит такое же имя хоста, она отклоняется и отображает предупреждение о том, что конфигурация с таким именем хоста уже существует.

Проблема в том, что мне нужен цикл foreach, который проверяет наличие ключа хеша, чтобы перезапустить цикл do-while, чтобы можно было попробовать другое имя хоста или пользователь мог ^C из сценария.

Вот фрагмент;

my $host;
do {
    print "Enter the hostname or IP of the ESXi server: ";
    chomp($host = <STDIN>);

    if ($host eq '') {
        print "You must enter a hostname or IP address!\n";
    } elsif ($host ne '') {

        # We need to catch duplicate configurations for we don't do the same work twice
        foreach (keys %config) {
            if ($config{$_}{host} ne $host) {
                last;
            } elsif ($config{$_}{host} eq $host) {
                warn "Configuration for $host already exists!\n";
            }
        }

        if ($ping_obj->ping($host)) {
            $config{$config_tag}{host} = $host;
        } elsif (! $ping_obj->ping($host)) {
            print RED . "Ping test for \'$host\' failed" . RESET . "\n";
        }

        $ping_obj->close();
    }
} while ($config{$config_tag}{host} eq 'undef');

Вот как выглядит хеш шаблона.

my %template = (
    host => 'undef',
    port => 'undef',
    login => {
        user => 'undef',
        password => 'undef',
    },
    options => {
        snapshots => "0",
        compress => "0",

        # This is expressed as an array
        exclude => 'undef',
    },
);

Ответы [ 3 ]

5 голосов
/ 22 декабря 2011

Если в Perl когда-либо используется оператор goto LABEL, то все.

do {
    START:     # could also go right before the "do"
    ...
    if (...) {
        warn "Configuration exists. Start over.\n";
        goto START;
    }
} while (...);
2 голосов
/ 22 декабря 2011

Почему у вас есть 3 elsif с, где подойдет простой else?
Я имею в виду, что они проверяют только на полную противоположность тому, на что тестировался соответствующий if.

if ($host eq '') {
    ...
} elsif ($host ne '') {
    ...
}
if ($config{$_}{host} ne $host) {
    ...
} elsif ($config{$_}{host} eq $host) {
    ...
}
if ($ping_obj->ping($host)) {
    ...
} elsif (! $ping_obj->ping($host)) {
    ...
}

Я бы использовал обычный цикл while вместо цикла do{...}while(...).

do{
  RESTART:
  if(...){
    goto RESTART;
  }
}while(...);

против

while(...){
  if(...){
    redo;
  }
}

В этом цикле вы используете только ключи %config, чтобы найти соответствующее значение, поэтому почему бы вам не использовать values %config.

foreach (keys %config) {
    if ($config{$_}{host} ne $host) {
        last;
    } elsif ($config{$_}{host} eq $host) {
        warn "Configuration for $host already exists!\n";
    }
}

против

for( values %config ){
  if( $_->{host} ne $host ){
    ...
  } else {
    ...
  }
}

Если вы используете 5.10.0 или более позднюю версию, вы можете вместо этого использовать интеллектуальное совпадение (~~) , что сделает более понятным то, что вы тестируете.

my @hosts = map{ $_->{host} } values %config;
if( $host ~~ @hosts ){
  ...
}
1 голос
/ 22 декабря 2011

Я не уверен, почему вы пытаетесь использовать do ... while, когда while кажется более естественным.

Некоторые заметки:

  • Вам не нужно перепроверять свои операторы if. Например, если $host eq '' верно, тогда $host ne '' должно быть ложным. По определению.
  • Если вы не собираетесь использовать $host вне цикла, что я предполагаю это не так, поскольку вы храните его в хэше, вы должны поместить my $host в цикл, чтобы ограничить область видимости.

Несколько советов:


while ($config{$config_tag}{host} eq 'undef') {
    print "Enter the hostname or IP of the ESXi server: ";
    chomp(my $host = <STDIN>);
    if ($host eq '') {
        print "You must enter a hostname or IP address!\n";
        redo;
    } else {
        # We need to catch duplicate configurations 
        my @host_list = map { $_->{host} } values %config 
        if ($host ~~ @host_list) {
            warn "Configuration for $host already exists!\n";
            redo;
        }
    }
    if ($ping_obj->ping($host)) {
        $config{$config_tag}{host} = $host;
    } else {
        print RED . "Ping test for \'$host\' failed" . RESET . "\n";
    }
    $ping_obj->close();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...