Why does 'continue' behave like 'break' in a Foreach-Object?

后端 未结 4 1310
被撕碎了的回忆
被撕碎了的回忆 2020-11-27 04:25

If I do the following in a PowerShell script:

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


        
相关标签:
4条回答
  • 2020-11-27 04:46

    Simply use the return instead of the continue. This return returns from the script block which is invoked by ForEach-Object on a particular iteration, thus, it simulates the continue in a loop.

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

    There is a gotcha to be kept in mind when refactoring. Sometimes one wants to convert a foreach statement block into a pipeline with a ForEach-Object cmdlet (it even has the alias foreach that helps to make this conversion easy and make mistakes easy, too). All continues should be replaced with return.

    P.S.: Unfortunately, it is not that easy to simulate break in ForEach-Object.

    0 讨论(0)
  • 2020-11-27 04:48

    A simple else statement makes it work as in:

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

    Or in a single pipeline:

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

    But a more elegant solution is to invert your test and generate output for only your successes

    1..100 | ForEach-Object {if ($_ % 7 -eq 0 ) {Write-Host "$($_) is a multiple of 7"}}
    
    0 讨论(0)
  • 2020-11-27 04:55

    Because For-Each object is a cmdlet and not a loop and continue and break do not apply to it.

    For example, if you have:

    $b = 1,2,3
    
    foreach($a in $b) {
    
        $a | foreach { if ($_ -eq 2) {continue;} else {Write-Host $_} }
    
        Write-Host  "after"
    }
    

    You will get output as:

    1
    after
    3
    after
    

    It is because the continue gets applied to the outer foreach loop and not the foreach-object cmdlet. In absence of a loop, the outermost level, hence giving you an impression of it acting like break.

    So how do you get a continue-like behaviour? One way is Where-Object of course:

    1..100 | ?{ $_ % 7  -eq 0} | %{Write-Host $_ is a multiple of 7}
    
    0 讨论(0)
  • 2020-11-27 04:59

    Another alternative is kind of a hack, but you can wrap your block in a loop that will execute once. That way, continue will have the desired effect:

    1..100 | ForEach-Object {
        for ($cont=$true; $cont; $cont=$false) {
            if ($_ % 7 -ne 0 ) { continue; }
            Write-Host "$($_) is a multiple of 7"
        }
    }
    
    0 讨论(0)
提交回复
热议问题