web-dev-qa-db-fra.com

Comment quitter ForEach-Object dans PowerShell

J'ai le code suivant:

$project.PropertyGroup | Foreach {
    if($_.GetAttribute('Condition').Trim() -eq $propertyGroupConditionName.Trim()) {
        $a = $project.RemoveChild($_);
        Write-Host $_.GetAttribute('Condition')"has been removed.";
    }
};

Question n ° 1: Comment puis-je quitter ForEach? J'ai essayé d'utiliser "break" et "continue", mais cela ne fonctionne pas.

Question n ° 2: j'ai constaté que je pouvais modifier la liste dans une boucle foreach ... Nous ne pouvons pas le faire comme cela en C # ... Pourquoi PowerShell nous permet-il de le faire?

50
Michael Sync

Objet 1. Placer un break dans la boucle foreach quitte la boucle, mais n'arrête pas le pipeline. On dirait que vous voulez quelque chose comme ça:

$todo=$project.PropertyGroup 
foreach ($thing in $todo){
    if ($thing -eq 'some_condition'){
        break
    }
}

Point n ° 2 PowerShell vous permet de modifier un tableau dans une boucle foreach par-dessus ce tableau, mais ces modifications ne prendront effet que lorsque vous aurez quitté la boucle. Essayez d’exécuter le code ci-dessous pour un exemple.

$a=1,2,3
foreach ($value in $a){
  Write-Host $value
}
Write-Host $a

Je ne peux pas dire pourquoi les auteurs de PowerShell ont autorisé cela, mais la plupart des autres langages de script ( Perl , Python et Shell) autorisent des constructions similaires.

88
smeltplate

Pour arrêter le pipeline dont ForEach-Object Fait partie, utilisez simplement l'instruction continue à l'intérieur du bloc de script sous ForEach-Object. continue se comporte différemment lorsque vous l'utilisez dans foreach(...) {...} et dans ForEach-Object {...}, raison pour laquelle c'est possible. Si vous souhaitez continuer à produire des objets dans le pipeline en supprimant certains des objets d'origine, la meilleure façon de le faire est de filtrer à l'aide de Where-Object.

8
darlove

Il y a des différences entre foreach et foreach-object.

Une très bonne description que vous pouvez trouver ici: MS-ScriptingGuy

Pour tester en PS, vous avez ici des scripts pour montrer la différence.

Pour chaque objet:

# Omit 5.
1..10 | ForEach-Object {
if ($_ -eq 5) {return}
# if ($_ -ge 5) {return} # Omit from 5.
Write-Host $_
}
write-Host "after1"
# Cancels whole script at 15, "after2" not printed.
11..20 | ForEach-Object {
if ($_ -eq 15) {continue}
Write-Host $_
}
write-Host "after2"
# Cancels whole script at 25, "after3" not printed.
21..30 | ForEach-Object {
if ($_ -eq 25) {break}
Write-Host $_
}
write-Host "after3"

pour chaque

# Ends foreach at 5.
foreach ($number1 in (1..10)) {
if ($number1 -eq 5) {break}
Write-Host "$number1"
}
write-Host "after1"
# Omit 15. 
foreach ($number2 in (11..20)) {
if ($number2 -eq 15) {continue}
Write-Host "$number2"
}
write-Host "after2"
# Cancels whole script at 25, "after3" not printed.
foreach ($number3 in (21..30)) {
if ($number3 -eq 25) {return}
Write-Host "$number3"
}
write-Host "after3"
5
Stoffi

Il n’existe AUCUN moyen simple de sortir d’un pipeline, mais vous pouvez appliquer des filtres à l’aide de Where-Object. Dans la mesure du possible, la meilleure solution consiste à convertir Foreach-Object (où les objets sont passés par pipe) dans une construction de boucle standard Foreach, par exemple:

Foreach-Object (objets passant dans le pipeline):

1..10 | Foreach-Object {
     if ($_ -eq 3) {return;}
     £_;
}
Write-Host "Only skips one iteration (iterates all 10 times)";

Converti en construction de boucle Foreach standard:

Foreach ($i in 1..10) { 
     if ($i -eq 3) {break;}
     $i;
}
Write-Host "Ends the loop after 2nd iteration (iterates only 2 times)";

Idem avec Where-Object filtre (où la conversion en boucle Foreach n'est pas possible):

1..10 | Where-Object {$_ -le 2} | Foreach-Object {
     $_;
}
Write-Host "Ends the loop after 2nd iteration (iterates only 2 times)";

HTH

0
Eddie Kumar