Mic*_*ync 52 powershell foreach
我有以下代码:
$project.PropertyGroup | Foreach {
if($_.GetAttribute('Condition').Trim() -eq $propertyGroupConditionName.Trim()) {
$a = $project.RemoveChild($_);
Write-Host $_.GetAttribute('Condition')"has been removed.";
}
};
Run Code Online (Sandbox Code Playgroud)
问题1:如何退出ForEach?我尝试使用"break"和"continue",但它不起作用.
问题2:我发现我可以在一个foreach循环中改变列表...我们不能像在C#中那样做...为什么PowerShell允许我们这样做?
小智 91
项目#1.break在foreach循环中放置确实退出循环,但它不会停止管道.听起来你想要这样的东西:
$todo=$project.PropertyGroup
foreach ($thing in $todo){
if ($thing -eq 'some_condition'){
break
}
}
Run Code Online (Sandbox Code Playgroud)
项目#2.PowerShell允许您foreach在该数组的循环内修改数组,但这些更改在您退出循环之后才会生效.尝试运行下面的代码作为示例.
$a=1,2,3
foreach ($value in $a){
Write-Host $value
}
Write-Host $a
Run Code Online (Sandbox Code Playgroud)
我无法评论为什么PowerShell的作者允许这样做,但大多数其他脚本语言(Perl,Python和shell)允许类似的结构.
zet*_*t42 10
有一种方法可以ForEach-Object在不引发异常的情况下中断。它采用了 的一个鲜为人知的功能Select-Object,即使用-First 参数,该功能实际上在处理了指定数量的管道项后会中断管道。
简化示例:
$null = 1..5 | ForEach-Object {
# Do something...
Write-Host $_
# Evaluate "break" condition -> output $true
if( $_ -eq 2 ) { $true }
} | Select-Object -First 1 # Actually breaks the pipeline
Run Code Online (Sandbox Code Playgroud)
输出:
$null = 1..5 | ForEach-Object {
# Do something...
Write-Host $_
# Evaluate "break" condition -> output $true
if( $_ -eq 2 ) { $true }
} | Select-Object -First 1 # Actually breaks the pipeline
Run Code Online (Sandbox Code Playgroud)
请注意,对 的赋值是为了隐藏由中断条件产生的$null输出。$true该值$true可以替换为42, "skip", "foobar",只要你能想到的。我们只需要通过管道传输一些东西,Select-Object这样它就会破坏管道。
要停止其中的管道,ForEach-Object只需使用continue脚本块下的语句ForEach-Object.continue当你在里面foreach(...) {...}和里面使用它时表现不同ForEach-Object {...},这就是为什么它是可能的.如果你想继续在管道中生成丢弃一些原始对象的对象,那么最好的方法是过滤掉使用Where-Object.
由于ForEach-Object是一个小命令,break并continue会表现不同,这里比与foreach 关键字。两者都将停止循环,但也会终止整个脚本:
休息:
0..3 | foreach {
if ($_ -eq 2) { break }
$_
}
echo "Never printed"
# OUTPUT:
# 0
# 1
Run Code Online (Sandbox Code Playgroud)
继续:
0..3 | foreach {
if ($_ -eq 2) { continue }
$_
}
echo "Never printed"
# OUTPUT:
# 0
# 1
Run Code Online (Sandbox Code Playgroud)
到目前为止,我还没有找到一种在不破坏脚本的情况下破坏 foreach 脚本块的“好”方法,除了“滥用”异常,尽管powershell 核心使用这种方法:
扔:
class CustomStopUpstreamException : Exception {}
try {
0..3 | foreach {
if ($_ -eq 2) { throw [CustomStopUpstreamException]::new() }
$_
}
} catch [CustomStopUpstreamException] { }
echo "End"
# OUTPUT:
# 0
# 1
# End
Run Code Online (Sandbox Code Playgroud)
另一种方法(并非总是可行)是使用foreach 关键字:
foreach:
foreach ($_ in (0..3)) {
if ($_ -eq 2) { break }
$_
}
echo "End"
# OUTPUT:
# 0
# 1
# End
Run Code Online (Sandbox Code Playgroud)
foreach和之间有差异foreach-object。
您可以在这里找到一个很好的描述:MS-ScriptingGuy
对于在PS中进行测试,这里有脚本来显示差异。
ForEach-Object:
# Omit 5.
1..10 | ForEach-Object {
if ($_ -eq 5) {return}
# if ($_ -ge 5) {return} # Omit from 5.
Write-Host $_
}
write-host "after1"
Run Code Online (Sandbox Code Playgroud)
# Cancels whole script at 15, "after2" not printed.
11..20 | ForEach-Object {
if ($_ -eq 15) {continue}
Write-Host $_
}
write-host "after2"
Run Code Online (Sandbox Code Playgroud)
# Cancels whole script at 25, "after3" not printed.
21..30 | ForEach-Object {
if ($_ -eq 25) {break}
Write-Host $_
}
write-host "after3"
Run Code Online (Sandbox Code Playgroud)
前言
# Ends foreach at 5.
foreach ($number1 in (1..10)) {
if ($number1 -eq 5) {break}
Write-Host "$number1"
}
write-host "after1"
Run Code Online (Sandbox Code Playgroud)
# Omit 15.
foreach ($number2 in (11..20)) {
if ($number2 -eq 15) {continue}
Write-Host "$number2"
}
write-host "after2"
Run Code Online (Sandbox Code Playgroud)
# Cancels whole script at 25, "after3" not printed.
foreach ($number3 in (21..30)) {
if ($number3 -eq 25) {return}
Write-Host "$number3"
}
write-host "after3"
Run Code Online (Sandbox Code Playgroud)
如果您坚持使用ForEach-Object,那么我建议添加一个“中断条件”,如下所示:
$Break = $False;
1,2,3,4 | Where-Object { $Break -Eq $False } | ForEach-Object {
$Break = $_ -Eq 3;
Write-Host "Current number is $_";
}
Run Code Online (Sandbox Code Playgroud)
上面的代码必须输出 1,2,3 然后跳过(break before) 4. 预期输出:
Current number is 1
Current number is 2
Current number is 3
Run Code Online (Sandbox Code Playgroud)