いつの間にかWindowsにいた「PowerShell」。何者?
OSはもっぱらwindowsを使っているが、コマンド自動実行といえばいまだにバッチ(*.bat)だと思ってた。
仕事で唐突に「PowerShell」なるものを使う機会があったので、いろいろいじってみた。
※そういえば、遠い昔にWSHとか使って気もするが、なんかいまいちだなーで終わった気がする。
1.Linuxっぽい
ちょっとだけLinuxをいじったことがあるけど、「bashに似ているな」が最初の感想。
たまたま見たシェルがパイプラインを多用していたのが原因かな。
その書き方が推奨なのかどうかはわからないけど、
処理順に書いてパイプラインでつないでもいいし、引数で受け取ってもいいみたい。
2.OS標準の開発環境がある
バッチみたいにテキストエディタでぽちぽちかと思いきや、
「Windows PowerShell ISE」というOS標準の開発環境があった(Windows10)。
インテリセンスもあるし、ブレークポイントも使えるので、それなりに便利。
3.配列のクセがすごい
多次元配列を使ったのだけど、
function setary
{
$arytmp = @()
$arytmp += ,@('elem1', 'val1')
return $arytmp
}
[String[][]]$ary = setary
Write-Host "=setary="
$ary | foreach -Process { Write-Host ("cnt[" + $_.Count + "],val[" + $_ + "]") }
function setary2
{
$arytmp = @()
$arytmp += ,@('elem1', 'val1')
$arytmp += ,@('elem2', 'val2')
return $arytmp
}
[String[][]]$ary = setary2
Write-Host "=setary2="
$ary | foreach -Process { Write-Host ("cnt[" + $_.Count + "],val[" + $_ + "]") }
この「setary」と「setary2」の結果がなぜか異なる。
要素1個か?要素2個か?の違いだけなんだけど。
以下は出力結果。
=setary=
cnt[1],val[elem1]
cnt[1],val[val1]
=setary2=
cnt[2],val[elem1 val1]
cnt[2],val[elem2 val2]
理由も調べてみたんだけど、わかるようなわからないような。
「List型を使え!」とかも散見。
List型?で気づいたのが次。
4.クラスが使える
使えるなんて全く思ってなかっただけにびっくり。
継承も可能。残念ながらインタフェースや抽象クラスは無いみたい。
オブジェクト指向のサンプル作ってみた。
# ファイルの内容を一定の形に整形して返却する関数
# (1) クラス関数(static)「isValid」で使用するクラスを候補から決定
# (2) 「(1)」のインスタンス生成
# (3) 「(2)」のクラス関数「execute」を実行
# (4) 「(3)」の戻り値を返却
function readFile([String]$filePath)
{
[OutputType([System.Collections.Generic.List[readResult]])]
# 読み取りクラス候補群
[Object[]]$readLogClasses = @([readLogSimple], [readLogSpecial], [readLogCsv])
# 読み取りに使用するクラスのインスタンス
[abstReadLog]$readLogObj = $null
# 使用する読み取りクラスを探索
foreach ($readLogC in $readLogClasses)
{
if ( $readLogC::isValid($filePath) )
{
$readLogObj = $readLogC::new()
break
}
}
# 結果を取得して返却
return $(if($null -eq $readLogObj){ New-Object 'System.Collections.Generic.List[readResult]' }else{ $readLogObj.execute($filePath) })
}
# なんちゃって抽象クラス
class abstReadLog
{
# 使用可否判定(抽象メソッド)
[bool] static isValid([String]$filePath) { return $false }
# コンストラクタ
abstReadLog()
{
$this.otherInit()
}
# その他初期化(抽象メソッド)
hidden [void]otherInit() { }
# 読込結果作成(抽象メソッド)
hidden [readResult]createReadResult([String]$filePath, [int]$remban, [exeTime]$startElem, [exeTime]$endElem) { return $null }
# 読込実行
[System.Collections.Generic.List[readResult]]execute([String]$filePath)
{
foreach( $lineFileData in Get-Content $filePath )
{
~なんやかんや~
$readResultElem = $this.createReadResult($filePath, ($readResultList.Count + 1), $startElem, $endElem)
$readResultList.Add($readResultElem)
}
return $readResultList
}
}
# 子クラス1
class readLogSimple : abstReadLog
{
# 使用可否判定
[bool] static isValid([String]$filePath)
{
[bool]$judge = $false
~なんやかんや~
return $judge
}
# その他初期化
hidden [void]otherInit() { }
# 読込結果作成
hidden [readResult]createReadResult([String]$filePath, [int]$remban, [exeTime]$startElem, [exeTime]$endElem)
{
[String]$taskName = $startElem.taskName + "[" + $startElem.sts + "/" + $endElem.sts + "]"
return [readResult]::new($filePath, $remban, $taskName, $startElem.exeDateTime, $endElem.exeDateTime)
}
}
5.感想
クラスが使えるというので、いろいろいじってたら、楽しくなってきた。
ただ、暗黙型変換はどうしても慣れない。型を宣言したくなってしょうがない。
バッチで小難しいことをやろうとすると、ぐちゃぐちゃになりがちだけど、
PowerShellだと、それなりにきれいなコードでかなりのことができそう。
使用頻度は高まってくるのかな?