Powershellあれこれ

本当はPythonが好きなのですが、Windowsであれば環境構築しなくても使えることが多いスクリプト言語 ということでPowershellを愛用しています。最近使ってるのをちょこっとメモ書き程度に

profile.ps1関係

よく使うユーティリティ関係は入れておくと大変便利

function edit([string]$str){
 $cmd = "C:\sakura\sakura.exe" + " `"" + $str + "`""
 Invoke-Expression $cmd
}

10進数⇔6進数変換は多用するなら入れておくと捗ります

function hex2dec([string}$hex){
 [convert]::ToInt32($hex,16)
}

function dec2hex([int]$dec){
 if( $dec -gt [convert]::ToInt32("FFFF",16) ) {
  $dec.ToString("X5")
 }else {
  $dec.ToString("X4")
 }
}

range関数が使いたい

pythonのrange関数は大変便利な関数でして、

for i in range(10):
 print i

とかそういう使い方がサンプルコードで良く載っています。
これと似たようなことをPowershellでする場合は範囲指定演算子というのがあって、

foreach($i in (0..9)){
 Write-Host "$i"
}

などで似たようなことができます。
が、以下のコードと同じ事はできません。

for i in range(0,10,2):
 print i

刻み幅が指定できないのは案外痛いので、何とかしましょう。純粋に方法がない以上、結局はforループでオブジェクトを生成することになります。

$ret = @()
for($i = $start; $i -lt $stop; $i += $step){
 $ret += $i
}

基本はこれだけです。あとは、引数によるオーバーライドに相当する機能を実装しておきます。

function range([int]$start=0; [int]$stop=0; [int]$step=0){
 $ret = @()

 # step=0なら空配列を返す
 if($step -eq 0){ return $ret; }

 # 開始番号>終了番号 && 増分が正
 elseif($start -le $stop -and $step -lt 0){ return $ret; }

 # 開始番号のみ指定された場合は0からその番号まで
 elseif($stop -eq 0 -and $step -ge 1){
  $stop = $start
  $start = 0
 }

 # 増分の正/負で切り替え
 if($step -ge 1){
  for($i = $start; $i -lt $stop; $i += $step){
   $ret += $i
  }
 }
 else{
  for($i = $start; $i -gt $stop; $i += $step){
   $ret += $i
  }
 }
 return $ret
}

これでpythonライクなrange関数になりました。

組み合わせ

この辺を使って何がしたいかというと、16進数である値からある値までのデータシートを作成するとき、要素列のインデックスが欲しかったのです。つまり、

 range (hex2dec 8000) (hex2dec 9000) 16 | %{ dec2hex $_ } | Out-File index.csv

こういう事ができるようになります。ExcelVBAあたりでやればいいんでしょうけれど、使い慣れた言語でサクッと書いてしまった方が楽なのでこういう形になりました というお話です。