为啥“继续”在 Foreach-Object 中表现得像“中断”?
Posted
技术标签:
【中文标题】为啥“继续”在 Foreach-Object 中表现得像“中断”?【英文标题】:Why does 'continue' behave like 'break' in a Foreach-Object?为什么“继续”在 Foreach-Object 中表现得像“中断”? 【发布时间】:2011-12-07 06:47:54 【问题描述】:如果我在 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
,continue
似乎会跳出管道循环。
1..100 | ForEach-Object
if ($_ % 7 -ne 0 ) continue;
Write-Host "$($_) is a multiple of 7"
我能否在仍然执行 ForEach-Object 的同时获得类似 continue
的行为,这样我就不必破坏我的管道?
【问题讨论】:
这是一个页面,其中包含许多与foreach
一起使用的命令:techotopia.com/index.php/…
在这里找到了一个不错的解释和示例...powershell.com/cs/blogs/tips/archive/2015/04/27/…
链接已失效,其他链接并没有真正解释这一点。请问能再找一下吗?
【参考方案1】:
只需使用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
s 都应替换为return
。
P.S.:不幸的是,在ForEach-Object
中模拟break
并不容易。
【讨论】:
从OP所说的显然continue
可以用来模拟break
中的ForEach-Object
:)
@Richard Hauer 这样的continue
会破坏整个脚本,而不仅仅是使用它的ForEach-Object
。【参考方案2】:
因为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。在没有循环的情况下,最外层,因此给你的印象是它就像break
。
那么你如何获得类似continue
的行为呢?一种方式当然是Where-Object:
1..100 | ? $_ % 7 -eq 0 | %Write-Host $_ is a multiple of 7
【讨论】:
使用 Where-Object cmdlet 是一个不错的建议。在我的实际情况中,我认为将 if 语句之前的多行代码变成一长行难以阅读的代码是没有意义的。但是,这在其他情况下对我有用。 @JustinDearing -In my actual case, I don't think it makes sense to make the multiple lines of code preceding my if statement into a single long line of hard to read code.
你是什么意思?
@manojlds 也许他认为您的单行解决方案“难以阅读”,至少对我来说完全相反。做事的管道方式非常强大和清晰,是处理简单事情的正确方法。在 shell 中编写代码而不利用它是没有意义的。
在我的情况下这是正确的答案,添加一个 where 条件来过滤掉我将继续或返回的对象,这样我就不需要首先处理它们. +1
我真的很喜欢Where-Object
的建议,因为它允许您在执行其余代码的同时打印替代消息或记录它,这样您就不必多次循环遍历列表, 虽然听起来像 continue
或 return
立即退出循环,所以如果你有几个条件想要比较,你将不得不建立一个粗糙的组合 if
语句块或循环几次不同的对象列表。【参考方案3】:
一个简单的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"
【讨论】:
【参考方案4】:另一种选择是一种 hack,但您可以将块包装在一个循环中,该循环将执行一次。这样,continue
就会达到预期的效果:
1..100 | ForEach-Object
for ($cont=$true; $cont; $cont=$false)
if ($_ % 7 -ne 0 ) continue;
Write-Host "$($_) is a multiple of 7"
【讨论】:
坦率地说,这很丑 :) 而且不仅仅是一个 hack,因为你可以使用 foreach 循环而不是 foreach 对象。 @manojlds: 1..100 仅用于说明。 do while($False) 和 for 循环一样好用,而且更直观。以上是关于为啥“继续”在 Foreach-Object 中表现得像“中断”?的主要内容,如果未能解决你的问题,请参考以下文章
为啥在具有一级索引的 MultiIndex 列的 pandas DataFrame 中表现不同?
为啥 clojure 的地图在 println 中表现得那样?
如何在 PowerShell 中退出 ForEach-Object
为啥 `additionalProperties` 是在 Swagger/OpenAPI 2.0 中表示 Dictionary/Map 的方式