ForEach-Objectにおけるcontinueとbreakについて
ForEach-Object内でのcontinue
やbreak
に関する備忘録です.
PowerShellでパイプライン処理のfor文として ForEach-Object
をよく使います.これは foreach
や %
のエイリアスがあります.
この foreach
エイリアスと foreach(in)
は別物です.本文では foreach(in)
は次のような構文を指しているとします.
foreach ($i in $arr) {
}
ForEach-Object
は便利な反面、誤解を招きやすいものだと思います .
実際、AIチャットも見当違いな回答をしていましたし、ネットでも間違った内容が見受けられました.
かくいう私も絶対の確信をもっていっているわけではないので、ご了承ください.動作環境はPowerShell7.4.5
です.
ForEach-Object に continue や break は使えない
これがすべてです.使えるのは return
です.ForEach-Object
はパイプライン処理であって、continue
やbreak
はパイプラインに直接作用しません.
continue
やbreak
が作用するのは内側のループ処理に対してです.ちなみに、ループがなければプログラム全体に作用しますので、その場合はプログラムが終了します.
たとえば次のプログラムでは、continue
が実行されたときにプログラムが終了します.
1..5 | ForEach-Object {
if ($_ -gt 3) {
continue
}
$_
}
Write-Host "CHECKPOINT"
この出力は次のようになります.
1
2
3
CHECKPOINT
は出力されません.これは break
でも同じです.
1..5 | ForEach-Object {
if ($_ -gt 3) {
break
}
$_
}
Write-Host "CHECKPOINT"
この場合、次のようにreturn
を使うと意図した動作になります.
1..5 | ForEach-Object {
if ($_ -gt 3) {
return
}
$_
}
Write-Host "CHECKPOINT"
この出力は次のようになります.
1
2
3
CHECKPOINT
このコードではすべてのパイプラインが実行されていることに注意してください.5回処理されています.
break
のように中断されるわけではありません.
continue
やbreak
を使いたい場合は、ループ回数が分かっているなら foreach(in)
を使うか for
文を使いましょう.
では、パイプライン処理で中断させたいときはどうすればいいでしょうか.1つの方法としてパイプラインの外にループを入れてbreak
することです.
do {
1..5 | ForEach-Object {
if ($_ -gt 3) {
break
}
$_
}
} while ($false)
Write-Host "CHECKPOINT"
この出力は次のようになります.
1
2
3
CHECKPOINT
continue
やbreak
はForEach-Object
に対して使いたくなるし、foreach
というエイリアスもあって間違えやすいですよね.
以上です.