Si je fais ce qui suit dans un script PowerShell:
$range = 1..100
ForEach ($_ in $range){
if ($_ % 7 -ne 0 ) { continue; }
Write-Host "$($_) is a multiple of 7"
}
Je reçois le résultat attendu de:
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
Cependant, si j'utilise un pipeline et ForEach-Object
, continue semble sortir de la boucle de pipeline.
1..100 | ForEach-Object {
if ($_ % 7 -ne 0 ) { continue; }
Write-Host "$($_) is a multiple of 7"
}
Ma question est la suivante: puis-je avoir un comportement semblable à celui que je garde tout en continuant à faire ForEach-Object, afin de ne pas avoir à rompre mon pipeline?
Utilisez simplement la return
au lieu de la continue
. Cette return
retourne du bloc de script appelé par ForEach-Object
lors d'une itération particulière. Elle simule donc la continue
dans une boucle.
1..100 | ForEach-Object {
if ($_ % 7 -ne 0 ) { return }
Write-Host "$($_) is a multiple of 7"
}
Il faut garder cela à l’esprit lors de la refactorisation. Parfois, on veut convertir un bloc d'instructions foreach
en un pipeline avec une applet de commande ForEach-Object
(il a même le pseudonyme foreach
qui facilite la conversion et les erreurs, aussi). Tous les continue
doivent être remplacés par return
.
P.S. Malheureusement, il n’est pas si facile de simuler break
dans ForEach-Object
.
Parce que For-Each
objet est une applet de commande et non une boucle et continuer/interrompre ne lui est pas applicable.
Par exemple, si vous avez:
$b = 1,2,3
foreach($a in $b){
$a | foreach { if($_ -eq 2) {continue;} else {write-Host $_} }
write-Host "after"
}
vous obtiendrez une sortie en tant que:
1
after
3
after
C'est parce que la commande continue est appliquée à la boucle externe foreach et non à l'applet de commande foreach-object. En l’absence de boucle, le niveau le plus à l’extérieur vous donne l’impression qu’il agit comme une pause.
Alors, comment obtenez-vous continuer comme comportement? Une façon est où-objet de cours:
1..100 | ?{ $_ % 7 -eq 0} | %{write-Host $_ is a mutliple of 7}
Une autre alternative est une sorte de bidouille, mais vous pouvez envelopper votre bloc dans une boucle qui s'exécutera une fois, ainsi continuer aura l'effet désiré:
1..100 | ForEach-Object {
for($cont=$true;$cont;$cont=$false){
if ($_ % 7 -ne 0 ) { continue; }
Write-Host "$($_) is a multiple of 7"
}
}
Une simple déclaration else le fait fonctionner tel quel
1..100 | ForEach-Object {
if ($_ % 7 -ne 0 ) {
#do nothing
} else {
Write-Host "$($_) is a multiple of 7"
}
}
ou dans un seul pipeline
1..100 | ForEach-Object { if ($_ % 7 -ne 0 ) {} else {Write-Host "$($_) is a multiple of 7"}}
mais une solution plus élégante consiste à inverser votre test et à générer une sortie uniquement pour vos succès.
1..100 | ForEach-Object {if ($_ % 7 -eq 0 ) {Write-Host "$($_) is a multiple of 7"}}