为什么在Foreach-Object中继续表现得像break?

时间:2011-10-13 20:24:27

标签: powershell foreach

如果我在powershell脚本中执行以下操作:

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

我得到了预期的输出:

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

但是,如果我使用管道和ForEach-Object,则继续似乎会突破管道循环。

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

我的问题是,我是否可以在继续使用ForEach-Object时获得类似行为,所以我不必分解我的管道?

4 个答案:

答案 0 :(得分:144)

只需使用return代替continue即可。此return从脚本块返回,该块由ForEach-Object在特定迭代中调用,因此,它模拟循环中的continue

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

在重构时要牢记这一点。有时,人们希望将foreach语句块转换为带有ForEach-Object cmdlet的管道(它甚至还有别名foreach,这有助于简化此转换并使错误变得容易)。所有continue都应替换为return

P.S。不幸的是,在break中模拟ForEach-Object并不容易。

答案 1 :(得分:17)

因为For-Each对象是cmdlet而不是循环,并且continue / break不适用于它。

例如,如果你有:

$b = 1,2,3

foreach($a in $b){

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

write-host "after"

}

您将获得输出:

1
after
3
after

这是因为continue应用于外部foreach循环而不是foreach-object cmdlet。没有循环,最外层,因此给你的印象就像休息一样。

那么你如何继续像行为一样?一种方式是在哪里 - 对象:

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

答案 2 :(得分:3)

另一种选择是一种黑客攻击,但是你可以将你的块包装在一个执行一次的循环中,这种方式继续将产生预期的效果:

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

答案 3 :(得分:0)

一个简单的else语句使它按原样工作

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

或在单个管道中

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

但是更优雅的解决方案是反转测试并仅为成功生成输出

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