wake-up-neo.com

Warum verhält es sich wie ein Bruch in einem Foreach-Objekt?

Wenn ich folgendes in einem Powershell-Skript mache:

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

Ich bekomme die erwartete Ausgabe von:

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

Wenn ich jedoch eine Pipeline und ForEach-Object verwende, scheint fortzufahren aus der Pipeline-Schleife auszubrechen.

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

Meine Frage lautet: Kann ich mich weiterhin mit ForEach-Object fortbewegen, sodass ich meine Pipeline nicht auflösen muss?

105
Justin Dearing

Verwenden Sie einfach die return anstelle der continue. Diese return wird aus dem Skriptblock zurückgegeben, der bei einer bestimmten Iteration von ForEach-Object aufgerufen wird, und simuliert somit die continue in einer Schleife.

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

Dies ist ein Problem, das beim Refactoring zu beachten ist. Manchmal möchte man einen foreach-Anweisungsblock mit einem ForEach-Object-Cmdlet in eine Pipeline konvertieren (er hat sogar den Aliasnamen foreach, der die Konvertierung vereinfacht und auch Fehler vereinfacht. Alle continue sollten durch return ersetzt werden.

P.S. Leider ist es nicht so einfach, break in ForEach-Object zu simulieren.

139
Roman Kuzmin

Da das For-Each-Objekt ein Cmdlet und keine Schleife und ein Weitersuchlauf ist, gilt dies nicht für das Objekt.

Zum Beispiel, wenn Sie:

$b = 1,2,3

foreach($a in $b){

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

write-Host "after"

}

sie werden ausgegeben als:

1
after
3
after

Der Grund ist, dass die Weitergabe auf die äußere Foreach-Schleife und nicht auf das Foreach-Object-Cmdlet angewendet wird. In Abwesenheit einer Schleife, äußerster Ebene, so dass Sie einen Eindruck davon bekommen, dass er wie ein Bruch wirkt.

Wie kommst du dann weiter? Ein Weg ist wo-Objekt des Kurses:

1..100 | ?{ $_ % 7  -eq 0} | %{write-Host $_ is a mutliple of 7}
17
manojlds

Eine andere Alternative ist eine Art Hack, aber Sie können Ihren Block in eine Schleife einwickeln, die einmal ausgeführt wird. Auf diese Weise wird fortfahren die gewünschte Wirkung erzielt:

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

Eine einfache else-Anweisung macht es so, wie es ist

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

oder in einer einzigen Pipeline

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

eine elegantere Lösung ist jedoch, den Test zu invertieren und nur für Ihre Erfolge zu generieren

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