PowerShellの制御構文
PowerShellでも一般的なプログラミング言語と同様に制御構文により構造化することができる。ただし様々なプログラミング言語の要素が入り混じったかたちになっているため、ほかのプログラミング言語に比べておかしなところもあるし、逆に書きやすい点もある。
条件分岐
もっともポピュラーな説明が条件分岐だろう。「もし~~ならば、ちがえば、」というものだ。C#と基本的に同じになるわけだが、波かっこは次の行へ移すことなくifのある同じ行へ書く。このあたりは設計者の思想のちがいなのかもしれない。文法として唯一C#と異なるのはelseとifの間にスペースがなく「elseif」で別条件を指定することだろう。この辺りは最初は戸惑うことがあるかもしれない。
if($a -eq 12){
Write-Output "12"
} elseif($a -eq "13") {
Write-Output "13"
} else {
Write-Output "not 12"
}
条件分岐には同様にswitchもある。ただ、caseを書かなくてよいこと、条件は波かっこによるスクリプトブロックになっていること、breakを書かなければフォールスルーが発生することがC#とは異なっている。
$a = 123
switch($a){
123 {
"1"
}
123 {
"2"
}
default {
"default"
}
}
# => [1, 2]
上記のswitchでは条件に合致する箇所が2回登場する。そのため、結果は「1」と「2」のいずれも出力されている。「1」のところで止めるべきであれば、breakを記述する必要がある。
特殊なswitch
特殊な、というのがなんのことだかわからないかもしれない。例えば、こういったケースだ。ある文字列変数の内容をチェックしたとき、最初の条件では「powershell」で始まるものはすべて、次の条件では「gitbook」を含むものはすべてという分岐をしたいとしよう。たいていはifで次のように記述するだろう。
$a = "powershell version6.0alpha"
if($a -like "powershell*"){
"powershell"
} elseif($a -like "*gitbook*"){
"git book"
} else {
"something"
}
ふつうはswitchでもこのように記述することはできない。しかしPowerShellではかなりおかしな方法でこれをswitchで記述することができる。それは、パラメータを与えるという方法だ。なんのことだかわからない?では次の例をご覧いただきたい。
$a = "powershell version6.0alpha"
switch -wild ($a){
"powershell*" {
"powershell"
}
"*gitbook*" {
"git book"
}
default {
"something"
}
}
# => "powershell"
上記では「-wild」というパラメータをswitch文に与えることでswitch文そのものの挙動を変えることができるという例だ。気持ち悪いかもしれない。ある一定のパターンであればこの方法で条件分岐をすることができる。でも待って。もっと複雑なパターンでやりたい、ということもあるだろう。そうしたときにはやはりifで…?いや、switchだ。次の例を見ていただきたい。
$a = "powershell version6.0alpha"
switch -reg ($a){
"^powershell\s*?[^\s]+$" {
"powershell"
}
".*gitbook.*" {
"git book"
}
default {
"something"
}
}
# => "powershell"
「-reg」パラメータを与えることで、正規表現をつかったパターンマッチを行うことができるようになる。便利なのか便利じゃないのかよくわからないところだ。用途を考えたところ、ぱっと思いつくのはユーザーエージェントの判別などだろうか。
値を返す条件分岐
ここまでご覧いただくと、PowerShellにはいわゆる3項演算子、エルビス演算子などと呼ばれる演算子が存在しないことに気が付くだろう。それはなぜなのか、というのがここでお伝えしたいことだ。PowerShellではifもswitchも値を返す。そのため、そうした演算子を必要としないのだ。さらに、このとき各条件分岐内のスクリプトブロックにおいて最後に評価されたもの、あるいは出力を伴ったものはすべて値として返される。出力を伴ったもの、という個所については後述する。
$myscript = "powershell"
$lang = if($myscript -in @("ruby", "python", "powershell", "groovy")){
"my script is light weight."
}
Write-Output $lang # => my script is light weight.
上記の例では、条件分岐の結果としてStringオブジェクトが記述されている。これによってif文としての出力はこのStringオブジェクトとなる。変数langへ出力されたオブジェクトは格納されるため、最終的にWrite-Outputコマンドレットで出力されたのは「my script is light weight.」ということになる。つまり、これを使うとelseifやelseを使ったとしてもswitchを使ったとしても、ある値を出力するため変数へ格納するなどのことができるようになる。この機能のため、3項演算子のようなものは存在しないのである。
反復
条件分岐とくれば、次は反復、繰り返しだろう。PowerShellでもwhileやforといった古典的な制御構文を使用することができる。
$i = 0
while($i -lt 10){
$i
} # => 0, 1, ... ,8 ,9
for($i = 0; $i -lt 10; $i++){
$i
}# => 0, 1, ... ,8 ,9
do {
"ya"
}while($i -eq 10) # => ya
繰り返しを継続するためにcontinue、途中で抜けるためのbreakも同様に利用することができる。
javascriptやC#、あるいはVBAなどでコレクションの内容を列挙していくようなときに使用される「foreach」がある。PowerShellにもこの「foreach」は存在するのだが、これは文ではない。PowerShellにおけるforeachは実は「ForEach-Object」コマンドレットの別名になっている。
$ls = Get-ChildItem
foreach($l in $ls){
if($l.Name -like "*vim*"){
break
} else {
$l.FullName
}
}
値を返す反復
条件分岐が値を返すのだから、当然かもしれない。変数へ格納するなどが可能になる。
$a = for($i = 1; $i -le 10; $i++){ $i }
$a # => [1..10]
反復ということなので連続したデータが返されることになり、System.Objectの配列が返される。スクリプトブロック内で出力されたオブジェクトが返されるわけなので、一括で加工した文字列を配列として受け取るなど活用方法はさまざまある。ただ、わたしはあまりやることはない。