2011-12-22 55 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