繁体   English   中英

如何在打破foreach循环后重新启动“do-while”循环?

[英]how can I restart a “do-while” loop after breaking out of a foreach loop?

我的配置脚本中有一小段代码,想法是加载配置然后检查每个密钥是否输入了主机名。 但是,如果发现配置包含相同的主机名,则会被拒绝,并显示一条警告消息,指出已存在具有该主机名的配置。

问题是我需要的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',
    },
);

如果在Perl中曾经使用过goto LABEL语句,那就是它。

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

为什么你有3个elsif s, 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(...);

VS

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";
    }
}

VS

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

如果您使用的是5.10.0或更高版本,则可以使用智能匹配( ~~ ,这样可以更清楚地了解您正在测试的内容。

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

我不确定你为什么要使用do ... whilewhile看起来更自然。

一些说明:

  • 您无需仔细检查if语句。 如果例如$host eq ''为真,则$host ne ''必须为false。 根据定义。
  • 如果你不打算在循环之外使用$host ,我认为你不是,因为你将它存储在散列中,你应该把my $host放在循环中,以限制范围。

一些技巧:

  • 您可以使用redo来重新启动循环。
  • 您可以使用智能匹配来取消for循环。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM