2011-10-13 5 views
89

Se faccio il seguente in uno script PowerShell:Perché continuare a comportarsi come una rottura in un oggetto Foreach?

$range = 1..100 
ForEach ($_ in $range){ 
    if ($_ % 7 -ne 0) { continue; } 
    Write-Host "$($_) is a multiple of 7" 
} 

ottengo l'output previsto di:

7 is a multiple of 7 
14 is a multiple of 7 
21 is a multiple of 7 
28 is a multiple of 7 
35 is a multiple of 7 
42 is a multiple of 7 
49 is a multiple of 7 
56 is a multiple of 7 
63 is a multiple of 7 
70 is a multiple of 7 
77 is a multiple of 7 
84 is a multiple of 7 
91 is a multiple of 7 
98 is a multiple of 7 

Tuttavia, se uso un oleodotto e ForEach-Object, continuo sembra uscire dalla loop della pipeline.

1..100 | ForEach-Object { 
    if ($_ % 7 -ne 0) { continue; } 
    Write-Host "$($_) is a multiple of 7" 
} 

Le mie domande è, posso avere un comportamento continuare così, mentre ancora facendo ForEach-Object, quindi non c'è bisogno di rottura la mia condotta?

+0

Ecco una pagina con un sacco di comandi da utilizzare con 'foreach': http://www.techotopia.com/index.php/Windows_PowerShell_1.0_Looping_with_the_for_and_foreach_Statements#Continuing_for_Loops – bgmCoder

+0

trovato una spiegazione decente e campione qui ... http: //powershell.com/cs/blogs/tips/archive/2015/04/27/understanding-break-continue-return-and-exit.aspx –

risposta

119

Utilizzare semplicemente return anziché continue. Questo return restituisce dal blocco di script che viene invocato da ForEach-Object in una particolare iterazione, pertanto simula lo continue in un ciclo.

1..100 | ForEach-Object { 
    if ($_ % 7 -ne 0) { return } 
    Write-Host "$($_) is a multiple of 7" 
} 

Questo è un trucco da tenere presente sul refactoring. A volte si vuole convertire un blocco di istruzioni foreach in una pipeline con un cmdlet ForEach-Object (ha anche l'alias foreach che aiuta a rendere questa conversione facile e rende facili anche gli errori). Tutto continue deve essere sostituito con return.

P.S. Sfortunatamente, non è così facile simulare lo break in ForEach-Object.

+1

Da quanto OP sta dicendo apparentemente 'continue' può essere usato per simulare un' break' in 'ForEach-Object' :) –

+2

@ Richard Hauer Tale' continue' interromperà l'intero script, non solo 'ForEach-Object' dove è solito. –

16

Perché l'oggetto For-Each è un cmdlet e non un ciclo e continue/interruzioni non si applicano ad esso.

Ad esempio, se si dispone di:

$b = 1,2,3 

foreach($a in $b){ 

$a | foreach { if($_ -eq 2) {continue;} else {write-host $_} } 

write-host "after" 

} 

otterrete output come:

1 
after 
3 
after 

E 'a causa della continua viene applicata al ciclo esterno foreach e non il cmdlet foreach-object . In assenza di un loop, livello più esterno, quindi dandoti l'impressione che agisca come una pausa.

Quindi come si continua a comportarsi come tale? Un modo è quello in cui oggetto naturalmente:

1..100 | ?{ $_ % 7 -eq 0} | %{write-host $_ is a mutliple of 7} 
+0

L'utilizzo del cmdlet Where-Object è un buon suggerimento. Nel mio caso concreto, non penso che abbia senso rendere le righe multiple di codice che precedono la mia istruzione if in un'unica lunga riga di codice difficile da leggere. Tuttavia, ciò funzionerebbe per me in altre situazioni. –

+0

@JustinDearing - 'Nel mio caso concreto, non penso che abbia senso rendere le righe multiple di codice che precedono la mia istruzione if in un'unica lunga riga di codice difficile da leggere."Cosa intendi? – manojlds

+3

@manojlds forse pensa che la tua soluzione a una linea sia "difficile da leggere", almeno per me è completamente il contrario. Il modo di fare pipeline per fare le cose è davvero potente e chiaro ed è l'approccio corretto per cose semplici come quelle. Scrivere codice nella shell senza approfittarne è inutile. – mjsr

3

Un'altra alternativa è una specie di hack, ma si può avvolgere il tuo blocco in un ciclo che sarà eseguita una volta, in questo modo continuare avrà l'effetto desiderato:

1..100 | ForEach-Object { 
    for($cont=$true;$cont;$cont=$false){ 
     if ($_ % 7 -ne 0) { continue; } 
     Write-Host "$($_) is a multiple of 7" 
     } 
} 
+3

Francamente, quello è brutto :) E non solo un hack perché al posto dell'oggetto foreach, si poteva anche usare un ciclo foreach. – manojlds

+0

@manojlds: 1..100 è solo a scopo illustrativo. do {} while ($ False) funziona altrettanto bene quanto per loop e bit più intuitivi. –

Problemi correlati