77

私は次のコードを持っています:

$project.PropertyGroup | Foreach-Object {
    if($_.GetAttribute('Condition').Trim() -eq $propertyGroupConditionName.Trim()) {
        $a = $project.RemoveChild($_);
        Write-Host $_.GetAttribute('Condition')"has been removed.";
    }
};

質問1:ForEach-Objectを終了するにはどうすればよいですか?「break」と「continue」を使ってみましたが、うまくいきません。

質問2:ループ内でリストを変更できることがわかりましたforeach... C#ではそのように変更できません... PowerShellで変更できるのはなぜですか?

4

10 に答える 10

125

まず第一に、実際のループでForeach-Objectなくbreak、それを呼び出すと、その後のステートメントにスキップするのではなく、スクリプト全体がキャンセルされます。

逆にbreak、実際のループcontinueでは期待どおりに動作します。foreach

アイテム#1。breakループ内にaを配置すると、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 の作成者がこれを許可した理由についてコメントすることはできませんが、他のほとんどのスクリプト言語 ( PerlPython、およびシェル) では同様の構造が許可されています。

于 2012-05-02T19:40:42.680 に答える
30

と の間には違いがforeachありforeach-objectます。

ここで見つけることができる非常に良い説明: MS-ScriptingGuy

PS でテストするために、ここに違いを示すスクリプトがあります。

ForEach-オブジェクト:

# 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"
于 2019-01-18T01:11:01.707 に答える
11

一部のパイプラインを停止するには、下のスクリプト ブロック内のForEach-Objectステートメントを使用します。内と内で使用すると動作が異なります。これが可能である理由です。元のオブジェクトの一部を破棄してパイプラインでオブジェクトの生成を続けたい場合は、 を使用して除外するのが最善の方法です。continueForEach-Objectcontinueforeach(...) {...}ForEach-Object {...}Where-Object

于 2014-12-24T17:15:01.973 に答える
4

ForEach-Objectの使用を主張する場合は、次のような「ブレーク条件」を追加することをお勧めします。

$Break = $False;

1,2,3,4 | Where-Object { $Break -Eq $False } | ForEach-Object {

    $Break = $_ -Eq 3;

    Write-Host "Current number is $_";
}

上記のコードは、1、2、3 を出力してから、4 をスキップ (前にブレーク) する必要があります。期待される出力:

Current number is 1
Current number is 2
Current number is 3
于 2020-05-25T02:55:30.020 に答える