ForEach-Object
cmdlet不带-Parallel
参数的情况下,它的实现是循环调用一个匿名函数,依次把管道传入的集合里的每个对象当作上下文来运行代码块。所以在代码块里使用return
,退出的是当前调用匿名函数的作用域,外层循环继续对下个传入对象调用匿名函数。下面是实验:
"A", "B", "C", "D" | ForEach-Object {
if ($_ -eq "C") {
Write-Host "嘿嘿嘿,C被我跳过啦!"
return
}
Write-Host $_
}
输出如下:
PS C:\Users\Curious\Desktop> .\test.ps1
A
B
嘿嘿嘿,C被我跳过啦!
D
综上,在ForEach-Object
cmdlet的PROCESS代码块中使用return
,脚本的行为类似于在for循环语句中的continue
关键字。
PowerShell中不止有ForEach-Object
这个cmdlet,还有foreach
关键字,foreach
作为关键字,行为和for
是完全一样的,想达到提前进入下个循环项的目的,只能使用continue
。代码如下:
"A", "B", "C", "D" | ForEach-Object {
if ($_ -eq "C") {
Write-Host "嘿嘿嘿,C被我跳过啦!"
return
}
Write-Host $_
}
$collection = "E", "F", "G", "H"
foreach ($currentItemName in $collection) {
if ($currentItemName -eq "G") {
Write-Host "呵呵,我也会跳过G。"
continue
}
Write-Host $currentItemName
}
输出:
PS C:\Users\Curious\Desktop> .\test.ps1
A
B
嘿嘿嘿,C被我跳过啦!
D
E
F
呵呵,我也会跳过G。
H
需要注意的一点是,foreach
语句的形式跟ForEach-Object
有很大的区别,写脚本的时候要分清写的到底是foreach
还是ForEach-Object
才能决定用return
还是continue
。
这是一个很容易混淆的问题,因为实际上只有ForEach-Object
可以接受管道输入,foreach
语句是不行的,但假如我们写出以下形式的代码,却也可以正常运行。原因是写在管道中的foreach
和%
都被当作ForEach-Object
的Alias,实际上运行的还是ForEach-Object
。这些易混淆的习惯写法在VSCode的PowerShell插件里会被提示。PowerShell是我最喜欢的脚本语言,但草率的内置alias破坏了它的完美,关于这一点,可以参考curl作为内置命令alias引起的争议。
"A", "B", "C", "D" | foreach {
if ($_ -eq "C") {
Write-Host "嘿嘿嘿,C被我跳过啦!"
return
}
Write-Host $_
}
"A", "B", "C", "D" | % {
if ($_ -eq "C") {
Write-Host "嘿嘿嘿,C被我跳过啦!"
return
}
Write-Host $_
}