102 votes

Comment sortir de ForEach-Object dans PowerShell

J'ai le code suivant :

$project.PropertyGroup | Foreach-Object {
    if($_.GetAttribute('Condition').Trim() -eq $propertyGroupConditionName.Trim()) {
        $a = $project.RemoveChild($_);
        Write-Host $_.GetAttribute('Condition')"a été supprimé.";
    }
};

Question #1 : Comment puis-je sortir de ForEach-Object ? J'ai essayé d'utiliser "break" et "continue", mais cela ne fonctionne pas.

Question #2 : J'ai découvert que je peux modifier la liste dans une boucle foreach... Nous ne pouvons pas le faire de cette manière en C#... Pourquoi PowerShell nous permet-il de le faire ?

6voto

Rikki Rockett Points 1774

Si vous insistez pour utiliser ForEach-Object, alors je suggère d'ajouter une "condition de sortie" comme ceci :

$Break = $False;

1,2,3,4 | Where-Object { $Break -Eq $False } | ForEach-Object {

    $Break = $_ -Eq 3;

    Write-Host "Le numéro actuel est $_";
}

Le code ci-dessus doit afficher 1,2,3 puis sauter (sortir avant) 4. Sortie attendue :

Le numéro actuel est 1
Le numéro actuel est 2
Le numéro actuel est 3

4voto

ThePennyDrops Points 91

Voici une approche suggérée à la question n°1 que j'utilise si je souhaite utiliser la cmdlet ForEach-Object. Cela ne répond pas directement à la question car cela ne SORT pas du pipeline. Cependant, cela peut avoir l'effet désiré en Q#1. Le seul inconvénient qu'un amateur comme moi peut voir est lors du traitement de grandes itérations de pipeline.

    $zStop = $false
    (97..122) | Where-Object {$zStop -eq $false} | ForEach-Object {
    $zNumeric = $_
    $zAlpha = [char]$zNumeric
    Write-Host -ForegroundColor Yellow ("{0,4} = {1}" -f ($zNumeric, $zAlpha))
    if ($zAlpha -eq "m") {$zStop = $true}
    }
    Write-Host -ForegroundColor Green "Ma version de PS = 5.1.18362.145"

3voto

Alex Hague Points 437

J'ai trouvé cette question en cherchant un moyen d'avoir un contrôle précis du flux pour sortir d'un bloc de code spécifique. La solution sur laquelle je me suis arrêté n'a pas été mentionnée...

Utilisation des étiquettes avec le mot-clé break

À partir de : about_break

Une instruction Break peut inclure une étiquette qui permet de sortir des boucles imbriquées. Une étiquette peut spécifier n'importe quel mot-clé de boucle, tel que Foreach, For ou While, dans un script.

Voici un exemple simple

:myLabel for($i = 1; $i -le 2; $i++) {
        Write-Host "Itération: $i"
        break myLabel
}

Write-Host "Après la boucle for"

# Résultats :
# Itération: 1
# Après la boucle for

Et ensuite un exemple plus compliqué qui montre les résultats avec des étiquettes imbriquées et en les rupturant chacune.

:outerLabel for($outer = 1; $outer -le 2; $outer++) {

    :innerLabel for($inner = 1; $inner -le 2; $inner++) {
        Write-Host "Extérieur: $outer / Intérieur: $inner"
        #break innerLabel
        #break outerLabel
    }

    Write-Host "Après la boucle intérieure"
}

Write-Host "Après la boucle extérieure"

# Les deux ruptures sont commentées
# Extérieur: 1 / Intérieur: 1
# Extérieur: 1 / Intérieur: 2
# Après la boucle intérieure
# Extérieur: 2 / Intérieur: 1
# Extérieur: 2 / Intérieur: 2
# Après la boucle intérieure
# Après la boucle extérieure

# Résultats de break innerLabel
# Extérieur: 1 / Intérieur: 1
# Après la boucle intérieure
# Extérieur: 2 / Intérieur: 1
# Après la boucle intérieure
# Après la boucle extérieure

# Résultats de break outerLabel
# Extérieur: 1 / Intérieur: 1
# Après la boucle extérieure

Vous pouvez également l'adapter pour fonctionner dans d'autres situations en enveloppant des blocs de code dans des boucles qui ne s'exécuteront qu'une seule fois.

:myLabel do {
    1..2 | % {

        Write-Host "Itération: $_"
        break myLabel

    }
} while ($false)

Write-Host "Après la boucle do while"

# Résultats :
# Itération: 1
# Après la boucle do while

0voto

Eddie Kumar Points 364

Vous avez deux options pour sortir brusquement du pipeline ForEach-Object en PowerShell:

  1. Appliquer la logique de sortie dans Where-Object d'abord, puis transmettre les objets à Foreach-Object, ou
  2. (si possible) convertir Foreach-Object en une structure de boucle standard Foreach.

Voyons des exemples: Les scripts suivants sortent de la boucle Foreach-Object après la 2è itération (c'est-à-dire le pipeline itère seulement 2 fois) :

Solution-1: utilisez le filtre Where-Object AVANT Foreach-Object:

[boolean]$exit = $false;
1..10 | Where-Object {$exit -eq $false} | Foreach-Object {
     if($_ -eq 2) {$exit = $true}    #OU $exit = ($_ -eq 2);
     $_;
}

OU

1..10 | Where-Object {$_ -le 2} | Foreach-Object {
     $_;
}

Solution-2: Converti Foreach-Object en une structure de boucle standard Foreach:

Foreach ($i in 1..10) { 
     if ($i -eq 3) {break;}
     $i;
}

PowerShell devrait vraiment offrir un moyen plus simple de sortir ou de break à l'intérieur du corps d'un pipeline Foreach-Object. Note: return ne sort pas, il saute seulement une itération spécifique (similaire à continue dans la plupart des langages de programmation), voici un exemple de return:

Write-Host "Ce qui suit sautera une seule itération (effectivement itère 10 fois)";
1..10 | Foreach-Object {
     if ($_ -eq 3) {return;}  #sauter seulement la 3è itération.
     $_;
}

0voto

Vopel Points 81

Alors que ceci est un peu astucieux, cela fonctionne :

$array = 'a'..'z'
:pipe do{
    $array | ForEach-Object {
        $_
        if ($_ -eq 'c') {
            break :pipe
        }
    }
} until ($true)

Sortie :
a
b
c

Le code peut également être facilement condensé, comme ceci :

$array = 'a'..'z'
:_ do{ $array | ForEach-Object {
    $_
    if ($_ -eq 'c') {
        break :_
    }
}}until(1)

# OU :
#}}until({})
# pas sûr pourquoi {} évalue à True, mais peu importe
# tout ce qui évalue à True fonctionnera, par exemple : !''

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X