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を実行している間に継続的な動作を取得できるので、パイプラインを分割する必要はありませんか?
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
コマンドレットを使用してパイプラインに変換したい場合があります(エイリアスforeach
もあり、この変換が簡単になり、ミスも簡単になります)。すべてのcontinue
はreturn
に置き換える必要があります。
追伸残念ながら、ForEach-Object
でbreak
をシミュレートするのはそれほど簡単ではありません。
For-Each
オブジェクトはコマンドレットであり、ループではなく、続行/中断が適用されないためです。
たとえば、次の場合:
$b = 1,2,3
foreach($a in $b){
$a | foreach { if($_ -eq 2) {continue;} else {write-Host $_} }
write-Host "after"
}
次のように出力されます。
1
after
3
after
これは、foreach-objectコマンドレットではなく、外側のforeachループにcontinueが適用されるためです。ループが存在しない場合、最も外側のレベルであるため、ブレークのように動作する印象を与えます。
それでは、どのように行動のように継続しますか? 1つの方法は、where-object ofcourseです。
1..100 | ?{ $_ % 7 -eq 0} | %{write-Host $_ is a mutliple of 7}
別の代替手段は一種のハックですが、1回実行するループでブロックをラップすることができます。そうすることで、継続することで望ましい効果が得られます。
1..100 | ForEach-Object {
for($cont=$true;$cont;$cont=$false){
if ($_ % 7 -ne 0 ) { continue; }
Write-Host "$($_) is a multiple of 7"
}
}
単純な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"}}