Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

People also ask

How do you break a foreach object?

The Break statement is used to exit a looping statement such as a Foreach, For, While, or Do loop. When present, the Break statement causes Windows PowerShell to exit the loop. The Break statement can also be used in a Switch statement.

What does foreach object do?

Description. The ForEach-Object cmdlet performs an operation on each item in a collection of input objects. The input objects can be piped to the cmdlet or specified using the InputObject parameter.

Is there continue in PowerShell?

The Continue statement is used in PowerShell to return the flow of the program to the top of an innermost loop. This statement is controlled by the for, Foreach and while loop.

How do I use each in PowerShell?

foreach is an internal PowerShell keyword that's not a cmdlet nor a function. The foreach statement is always used in the form: foreach ($i in $array) . Using the example above, the $i variable represents the iterator or the value of each item in $path as it iterates over each element in the array.


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.


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}

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"}}

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"
    }
}