これまで繰り返し制御構文としてfor制御構文とwhile制御構文を取り上げた。書き方は異なるものの、for制御構文もwhile制御構文もできることはほとんど同じだ。

今回はその続きとしてforeach制御構文を紹介する。抽象度の高いプログラミング言語に馴れているならfor制御構文やwhile制御構文よりもforeach制御行文の方が馴れているかもしれない。

foreach制御構文

PowerShell Coreにおけるforeach制御構文の書き方は次のとおり。

foreach制御構文の基本的な書き方

foreach ($変数 in $コレクション) {
    処理
}

どのように動作するかは、次のようにforeach制御構文をfor制御構文で書き換えるとわかりやすいかもしれない。

foreach制御構文をfor制御構文で書き換えたサンプル

for ($カウント変数 = 0;
     $カウント変数 -lt $コレクション.length;
     $カウント変数++)
{
    $変数 = $コレクション[$カウント変数];

    処理
}

foreach制御構文では、コレクションの中の値が逐次変数に代入された状態でブロックの中が実行されるという動きが行われる。繰り返し処理はコレクションをベースにして行われることが多いので、これはなかなか理にかなった制御構文だ。実際の使用例を通じて使い方を見ていこう。

foreach制御構文の使い方

まず、次のようなもっとも基本的なforeach制御構文の使い方を見てみよう。次の例ではまず$cという配列を用意しており、中身はとんかつ、生姜焼き、焼き肉、豚汁という定食メニューとなっている。foreach ($i in $c) という書き方をすると、この定食メニューの中身が変数$iに順次代入されブロック内の処理が行われるようになる。

foreach制御構文の実行サンプル

PS /Users/daichi> $c = "とんかつ","生姜焼き","焼き肉","豚汁"
PS /Users/daichi> foreach ($i in $c) {
>> Write-Host $i"定食"
>> }
とんかつ定食
生姜焼き定食
焼き肉定食
豚汁定食
PS /Users/daichi>

上記例でなんとなくforeach制御構文の使い方がわかっただろう。コレクションの中身をひとつづつ変数に代入して、順次ブロックの中の処理を実行する。これがforeach制御構文だ。

foreach制御構文はコレクションの部分に変数ではなく、コレクションを返すコマンドレットを書くこともできる。次のサンプルではコレクション変数を書く部分にGet-ChildItemコマンドレットを記述してある。これでGet-ChildItemコマンドレットの実行結果(のコレクションの中身)が順次変数$iに代入された状態でブロック内の処理が実行されることになる。

foreach制御構文でコレクションの部分にコマンドレットを指定した場合のサンプル

PS /Users/daichi/Documents/tttcmds> Get-ChildItem .


    Directory: /Users/daichi/Documents/tttcmds


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       2016/12/21     13:09                bin
d-----       2016/12/21     13:09                include
d-----       2016/12/21     13:09                lib
d-----       2016/12/21     13:09                mk
d-----       2016/12/21     13:09                src
d-----       2016/12/21     13:09                tests
------       2016/12/21     13:09           1337 LICENSE
------       2016/12/21     13:09           1908 Makefile
------       2016/12/21     13:09           1420 Makefile.inc
------       2016/12/21     13:09           1348 README.md


PS /Users/daichi/Documents/tttcmds> foreach ($i in Get-ChildItem .) {
>> Write-Host $i
>> }
/Users/daichi/Documents/tttcmds/bin
/Users/daichi/Documents/tttcmds/include
/Users/daichi/Documents/tttcmds/lib
/Users/daichi/Documents/tttcmds/mk
/Users/daichi/Documents/tttcmds/src
/Users/daichi/Documents/tttcmds/tests
/Users/daichi/Documents/tttcmds/LICENSE
/Users/daichi/Documents/tttcmds/Makefile
/Users/daichi/Documents/tttcmds/Makefile.inc
/Users/daichi/Documents/tttcmds/README.md
PS /Users/daichi/Documents/tttcmds>

foreach制御構文を使うとコマンドレットの実行結果をそのまま繰り返し処理の対象とすることができるのでかなり強力だ。

for制御構文やwhile制御構文ではbreakとcontinueで繰り返し処理を抜けたり、次の処理に飛ばすことができた。breakが繰り返しの終了、continueが次の処理へスキップする指定だ。この機能はforeach制御構文でも同様。たとえば次のように$iが8だったらbreakを実行するといった処理を実行してみる。

条件を満たしたらbreakを実行するサンプル

PS /Users/daichi/Documents/tttcmds> $c = 1,2,3,4,5,6,7,8,9,10
PS /Users/daichi/Documents/tttcmds> foreach ($i in $c) {
>> if ($i -eq 8) {
>>     break
>> }
>> Write-Host $i
>> }
1
2
3
4
5
6
7
PS /Users/daichi/Documents/tttcmds>

条件に合致するとbreakが実行され繰り返し処理を抜けていることがわかる。次の例はcontinueを実行した場合だ。こちらでは変数$iの値が4よりも大きく8よりも小さい(つまり5、6、7の)場合にcontinueが実行され、次の処理へスキップが行われることになる。

条件を満たしたらcontinueを実行するサンプル

PS /Users/daichi/Documents/tttcmds> $c = 1,2,3,4,5,6,7,8,9,10
PS /Users/daichi/Documents/tttcmds> foreach ($i in $c) {
>> if ($i -gt 4 -and $i -lt 8) {
>>     continue
>> }
>> Write-Host $i
>> }
1
2
3
4
8
9
10
PS /Users/daichi/Documents/tttcmds>

continueはbreakとは異なり次の処理にスキップするだけでbreakのように繰り返し処理を抜けるわけではないので、コレクションの最後まで処理が行われていることを確認できる。

foreach制御構文は珍しい制御構文ではなく、多くのプログラミング言語に存在している一般的なものだ。シェルにも用意されている。基本的な制御構文としてぜひ抑えておきたい。

参考資料