How can I restart the do-while loop after exiting the foreach loop?

I have a small piece of code from my configuration script, the idea is that the configuration is loaded, and each key is checked against the entered host name. But if the configuration found contains the same host name, it is rejected and displays a warning message that a configuration with this name already exists.

The problem is that I need a foreach loop that checks for a hash key to restart the do-while loop so that I can try a different host name, or the user can ^C exit the script.

Here is a snippet:

 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'); 

Here's what the template hash looks like.

 my %template = ( host => 'undef', port => 'undef', login => { user => 'undef', password => 'undef', }, options => { snapshots => "0", compress => "0", # This is expressed as an array exclude => 'undef', }, ); 
+4
source share
3 answers

If Perl ever uses the goto LABEL expression, that is it.

 do { START: # could also go right before the "do" ... if (...) { warn "Configuration exists. Start over.\n"; goto START; } } while (...); 
+5
source

Why do you have 3 elsif where a simple else will be executed?
I mean, they only check what matches the tested 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)) { ... } 

I would use a regular while instead of a do{...}while(...) .

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

vs

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

In this loop, you only use the %config keys to find the associated value, so why not use the values %config .

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

vs

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

If you are using 5.10.0 or later, you can use smart matching ( ~~ ) instead, which would make it clearer what you are testing.

 my @hosts = map{ $_->{host} } values %config; if( $host ~~ @hosts ){ ... } 
+2
source

I'm not sure why you are trying to use do ... while when while seems more natural.

Some notes:

  • You do not need to double check your if statements. If, for example, $host eq '' true, then $host ne '' should be false. A-priory.
  • If you are not going to use $host outside the loop, which I assume you are not, since you store it in a hash, you must put my $host inside the loop to limit the scope.

Some tips:


 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(); } 
+1
source

Source: https://habr.com/ru/post/1387480/


All Articles