私は次のコードを持っています:
$project.PropertyGroup | Foreach {
if($_.GetAttribute('Condition').Trim() -eq $propertyGroupConditionName.Trim()) {
$a = $project.RemoveChild($_);
Write-Host $_.GetAttribute('Condition')"has been removed.";
}
};
質問#1:ForEachを終了するにはどうすればよいですか? 「break」と「continue」を使用してみましたが、機能しません。
質問#2:foreach
ループ内でリストを変更できることがわかりました... C#ではそのようにできません...なぜPowerShellでできるのですか?
アイテム#1。 break
ループ内にforeach
を配置すると、ループは終了しますが、パイプラインは停止しません。次のようなものが欲しいようです:
$todo=$project.PropertyGroup
foreach ($thing in $todo){
if ($thing -eq 'some_condition'){
break
}
}
アイテム#2。 PowerShellでは、その配列に対するforeach
ループ内の配列を変更できますが、ループを終了するまでそれらの変更は有効になりません。例として以下のコードを実行してみてください。
$a=1,2,3
foreach ($value in $a){
Write-Host $value
}
Write-Host $a
PowerShellの作成者がこれを許可した理由についてはコメントできませんが、他のほとんどのスクリプト言語( Perl 、 Python およびShell)は同様の構成を許可します。
ForEach-Object
が属するパイプラインを停止するには、ForEach-Object
の下のスクリプトブロック内でステートメントcontinue
を使用します。 continue
は、foreach(...) {...}
とForEach-Object {...}
で使用すると動作が異なります。これが可能である理由です。元のオブジェクトの一部を破棄してパイプラインでオブジェクトの生成を続けたい場合、Where-Object
を使用して除外するのが最善の方法です。
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"
# Cancels whole script at 15, "after2" not printed.
11..20 | ForEach-Object {
if ($_ -eq 15) {continue}
Write-Host $_
}
write-Host "after2"
# Cancels whole script at 25, "after3" not printed.
21..30 | ForEach-Object {
if ($_ -eq 25) {break}
Write-Host $_
}
write-Host "after3"
foreach
# Ends foreach at 5.
foreach ($number1 in (1..10)) {
if ($number1 -eq 5) {break}
Write-Host "$number1"
}
write-Host "after1"
# Omit 15.
foreach ($number2 in (11..20)) {
if ($number2 -eq 15) {continue}
Write-Host "$number2"
}
write-Host "after2"
# Cancels whole script at 25, "after3" not printed.
foreach ($number3 in (21..30)) {
if ($number3 -eq 25) {return}
Write-Host "$number3"
}
write-Host "after3"
パイプラインから抜け出す簡単な方法はありませんが、Where-Object
を使用してフィルターを適用できます。可能な場合、最良の解決策は、Foreach-Object
(パイプを使用してオブジェクトが渡される)を標準のForeach
ループ構造に変換することです。次に例を示します。
Foreach-Object
(パイプラインでオブジェクトを渡す):
1..10 | Foreach-Object {
if ($_ -eq 3) {return;}
£_;
}
Write-Host "Only skips one iteration (iterates all 10 times)";
標準のForeach
ループ構造に変換:
Foreach ($i in 1..10) {
if ($i -eq 3) {break;}
$i;
}
Write-Host "Ends the loop after 2nd iteration (iterates only 2 times)";
Where-Object
フィルターを使用した場合も同じです(Foreach
ループへの変換は不可能です):
1..10 | Where-Object {$_ -le 2} | Foreach-Object {
$_;
}
Write-Host "Ends the loop after 2nd iteration (iterates only 2 times)";
HTH