Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/maven/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Powershell 为什么';继续';表现得像';中断';在Foreach对象中?_Powershell_Foreach - Fatal编程技术网

Powershell 为什么';继续';表现得像';中断';在Foreach对象中?

Powershell 为什么';继续';表现得像';中断';在Foreach对象中?,powershell,foreach,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

如果在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对象
continue
似乎打破了管道循环

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

我是否可以在仍对每个对象执行操作时获得类似于
continue
的行为,这样就不必中断管道?

因为每个
对象的
都是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对象cmdlet。在没有循环的情况下,是最外层的级别,因此给人的印象是它的行为类似于
break

那么,您如何获得类似于
的行为?其中一种方法当然是:

1..100 | ?{ $_ % 7  -eq 0} | %{Write-Host $_ is a multiple of 7}

另一种选择是一种黑客攻击,但您可以将块封装在一个循环中,该循环将执行一次。这样,
继续
将达到预期效果:

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

只需使用
返回
而不是
继续
。该
return
从脚本块返回,该脚本块在特定迭代中由
ForEach对象
调用,因此,它模拟循环中的
continue

1..100 | ForEach-Object {
    if ($_ % 7 -ne 0 ) { return }
    Write-Host "$($_) is a multiple of 7"
}
重构时要记住一个问题。有时需要使用
foreach对象
cmdlet将
foreach
语句块转换为管道(它甚至有别名
foreach
,这有助于简化转换,也容易出错)。所有
continue
s应替换为
return


注:不幸的是,在
中为每个对象模拟
中断
并不是那么容易的

一个简单的
否则
语句使其工作如下:

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

使用Where-Object cmdlet是一个很好的建议。在我的实际情况中,我认为将if语句前面的多行代码变成一行难以阅读的代码是没有意义的。但是,在其他情况下,这对我来说是可行的。@justinearing-
在我的实际案例中,我认为将if语句前面的多行代码变成一行难以阅读的代码是没有意义的。
你是什么意思?@manojlds也许他认为你的一行解决方案是“难以阅读的”,至少对我来说完全相反。管道方式做事情是非常强大和清晰的,对于这样简单的事情是正确的方法。在shell中编写代码而不利用这一点是毫无意义的。在我的例子中,这是正确的答案,添加一个where条件来过滤掉我将要继续或返回的对象,这样我就不需要首先处理它们+1我非常喜欢
Where Object
的建议,因为它允许您在执行其余代码的同时打印备用消息或记录它,这样您就不必在列表中循环多次,而听起来像
continue
return
立即退出循环,因此,如果你想比较两个条件,你就必须建立一个粗糙的组合
if
语句块,或者在对象列表中循环几次。坦率地说,这很难看:)而不仅仅是一个hack,因为不是foreach对象,您也可以使用foreach循环。@manojlds:1..100仅用于说明。do{}while($False)对于循环同样有效,而且更直观。下面是一个页面,其中有许多用于
foreach
:在这里找到了一个不错的解释和示例。。。链接已经失效,其他链接并不能真正解释这一点。请你再找一遍好吗?根据OP的说法,显然
continue
可以用来模拟
ForEach对象中的
中断
)@Richard Hauer这样的
continue
将中断整个脚本,而不仅仅是
ForEach对象的使用位置。