PowerShellは出来る子なのではないか

WindowsにはまともなCUIが、もといスクリプティングな環境がない。そう考えている時期が僕の今日まででした。

今日、会社の都合でPowerShellスクリプトを書いたのですが、こいつが思ってた以上に好感触。
文法もC#シェルスクリプトを合わせたような感じ。オブジェクトベースのシェルということで、パイプにしても、シェルスクリプトがテキストをつないでいくのに対して、powershellLINQ書いてる気分。
何よりも.NETerなら学習コストがとても低い!

手持ちにWindowsの環境がないで未検証のコードになってしまうが、例えば郵便番号とかのCSVを読み込んでなんか処理するようなものを書く場合

Import-Csv | ? {$_.郵便番号 -match "^19[4-7]-\d{4}$"} | % {$_.住所}

こんな感じで書けば、正規表現でマッチした郵便番号が存在するレコードのうち、住所だけを抜き出すことが出来ちゃう。
こういう作業を、cygwinとか入れたりせずにコマンドライン一発で出来てしまう。
いけてるのが、パイプで渡してるオブジェクトに対して、CSVをパースして定義しているカラム名を勝手にフィールドとして定義してくれているところ。これをC#LINQでやろうとするとDynamicを使うことになるのかしらん? awkだとこうはいかない

解説すると。
?{} の部分は、色々と書き方があるのですがwhere{}とも書くことが出来ます。要はfilter。
%{}はmapです。
ちなみに$_はパイプ処理時に暗黙に用意される変数で、渡される変数を示してる。Scalaで使う_みたいな感じだと思えばわかりやすい。

あと、awkっぽい文法が用意されております。

1..15 | % -Begin{[int]$total} {$total = $total + $_} -End{Write-Host $total}

こんな風に書くことも出来る。ちなみに、powershellはかなり色々な書き方が用意されていて、例えばパイプにしてもForeach-Objectと書けたり| foreachと書けたり| %と書けたりする。
awkっぽい部分も、別の関数に分けてしまって

function pipe() {
    begin {hoge}
    process {hoge}
    end {hoge}
}

とも書けるらしい。というかそもそも、-Beginとか明示しなくても、ScriptBlockを三つ渡してあげれば、勝手に判断してくれるらしい。出来る子だ。
あと文字列中の文字の展開も

$hoge="hoge"
$foo="foo"

Write-Host String::Format("hoge={0}, foo={1}", $hoge, $foo)
Write-Host "hoge={0}, foo={1}" -F $hoge, $foo
Write-Host "hoge=$hoge, foo=$foo" #シングルコーテーションだと展開されない

とまぁ.NETおなじみのString.formatからシェルっぽくそのまま展開とか色々出来る。あと変数には型を指定することも出来る。


そして.NETのライブラリは基本的に全て呼べる。
上では書いてないけど、関数の定義とかもC#チックですごくとっつきやすい。しかもその上で、シェルスクリプト風の文法にも対応している。コマンド自体の利便性を拡張するために、パイプ用のフィルターを別途定義したりできる。さらに、先のCSV-importみたいなものにしてもC#とかで自作して拡張できちゃう(多分)という。

正直、今まで触りもせずに馬鹿にしてきていたけど、*nixに負けないスクリプティング環境が手に入ったとさえ感じるでござる。ネットワーク系とかは……わかんないけど。
あとはもう少しまともなターミナルエミュレータさえ用意してくれれば、あるいはWIndowsプログラマブルな環境がそろう日が来るのかもしれない。

まぁその前にWindows買わないといけないけども。