2011-12-22 52 views
4

我的配置脚本中有一小段代码,想法是配置被加载,然后检查每个键是否已输入主机名。但是,如果发现某个配置包含相同的主机名,则它将被拒绝并显示一条警告消息,指出该主机名的配置已存在。如何在断开foreach循环后重新启动“do-while”循环?

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

这是应该做的:'eq'undef''?我希望你没有试图去检查这个值是否是未定义的,因为那不是那么做的。 – TLP 2011-12-22 00:41:30

+0

我正在检查它是否是'undef',但是它检查的散列是用值undef'硬编码的。 – ianc1215 2011-12-22 01:18:36

+0

不,不,不是,你要么检查它是否是'undef'(字符串),要么检查'undef'中的'未定义'。你的措辞是不明确的。 – TLP 2011-12-22 01:26:54

回答

5

如果在Perl中有一个goto LABEL语句的用法,就是这样。

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

如果将标签放在循环中,循环结束时标签将被销毁,对吗? – ianc1215 2011-12-22 01:19:37

+0

@Solignis - 不对。标签的范围规则有点复杂 - 请参阅perldoc中的详细信息 - 但可以在此“do-while”循环之前或之后执行“goto START”。 (这不是一个好地方,使用'goto') – mob 2011-12-22 03:25:49

+0

'perl -e'do {START:} while(0); goto START'' on 5.14打印出使用goto跳转到构造中在-e行1.已弃用(多次)。我完全认为它在5.18出现时将不再工作。事实上,在5.16出来后,我想我可能会把它放在[p5p]上(http://lists.perl.org/list/perl5-porters.html)。 – 2011-12-22 05:08:37

1

我不知道你为什么要使用do ... while,当while看起来更自然。

一些注意事项:

  • 你并不需要仔细检查您的if语句。如果例如$host eq ''为真,那么$host ne ''必须为假。每个定义。
  • 如果你不打算在循环外部使用$host,我假设你不是 ,因为你将它存储在散列中,所以你应该在循环内部放置my $host来限制范围。

一些提示:

  • 您可以使用redo重新启动循环。
  • 您可以使用smart matching来取消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(); 
} 
+0

'my @host_list = map {$ _-> {host}} values%config' – 2011-12-22 01:23:08

+0

@BradGilbert谢谢。当我重写代码时,我想我对删除按钮有点太急切了。 – TLP 2011-12-22 01:29:23

2

为什么你有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或更高版本,你可以使用一个smart match (~~)相反,这将使你测试更清楚什么。

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

%配置指向键不值。 '%config => server ## => host => $ address'服务器##是我需要使用循环提取的键。所以除非我错误地使用'values%config'对我来说什么都不会做。 – ianc1215 2011-12-22 04:13:03

+1

@Solignis在您的问题中包含的代码中,除了获取与其关联的值之外,您从未使用过任何键。如果你有,我会发布其他东西。 'map {$ _-> {host}} values%config'与map {$ config {$ _} {host}}键%config'相同,这实际上就是你在做的。 – 2011-12-22 04:25:56

+0

哦,我明白了,所以'%config'的值是'server ##'?对? – ianc1215 2011-12-22 04:35:31