『PowerShell実践ガイドブック』吉崎生(著)を読んだときのメモ

PowerShellは体系的に勉強しなくても、なんとなくそれなり使えていたので書籍を読む動機が乏しかったが、本書を読んで少し理解が深まったように思うのでメモしておこう。
本書は初級者が全てを一気に消化するには水準が高いが、意外にも最終章の「実世界のPoweShell」には初級者にとって参考になる情報があった。過去に配列を扱ったときに意図した通りに動かすことができなく、泥臭い方法で対応した記憶があるが、単一要素だと配列でなくなってしまうというのは知らなかった。

PS >function GetMyArray(){ return @(108) }
PS >$a = GetMyArray
PS >$a
108
PS >$a.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Int32                                    System.ValueType

PS >function GetMyArray2() { return @(108,109) }
PS >$b = GetMyArray2
PS >$b
108
109
PS >$b.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

GetMyArray2()は2要素を返すので受け取ったときも配列であるが、GetMyArray()は受け取ったときにInt32になってしまう。
これを回避するには、単項演算子","(カンマ)を使用すればよいらしい。(使い慣れた人には常識なのでしょうが・・・)

PS >function GetMyArray3(){ return ,@(108) }
PS >$c = GetMyArray3
PS >$c
108
PS >$c.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     Object[]                                 System.Array

GetMyArray3()から受け取った値は配列になっている。

また、配列に要素を追加するときは"+="を使っていたが、性能が問題になる場合は Listオブジェクトを利用するとよいらしい。
以下は

using namespace System.Collections.Generic

function list($size)
{
    $a = New-Object List[string]
    foreach($i in 1..$size){$a.Add("Hello $i")}
}

function arry($size)
{
    $a = @()
    foreach($i in 1..$size){$a += "Hello $i"}
}

$funcs = @("arry","list")
$sizes = 1..5 | % {[math]::pow(10,$_)}

foreach ( $func in $funcs )
{
    Write-Host "Function : " $func -background darkred

    foreach ( $i in $sizes )
    {
        $msg = "  Data Size : {0,6}" -f $i
        Write-Host $msg -background darkcyan
        (measure-command { & $func -Size $i}).TotalSeconds
    }
}

結果は以下の通りで、回数が大きくないときは体感できないと思うが、10万回のときは圧倒的な差になっている。
正直ここまで差ができるとは驚きである。ちなみに List でも += を使うと元の木阿弥らしい(試していません)。
PS >.\measure.ps1
Function : arry
Data Size : 10
0.0016263
Data Size : 100
0.0013971
Data Size : 1000
0.0382159
Data Size : 10000
3.16658
Data Size : 100000
445.67421
Function : list
Data Size : 10
0.0022096
Data Size : 100
0.0014394
Data Size : 1000
0.0017029
Data Size : 10000
0.0280322
Data Size : 100000
0.0793438

UnixのシェルからPowerShellのシェルに切り替えたときはパイプラインの中を流れるのはオブジェクトであるというのには戸惑ったが、
変数スコープに関して「子は親の変数を参照できるが変更はできない。」というのはつい忘れてしまう。
ときどき、気がつかない間にパイプラインの中を文字列が流れていると意識になってしまうことがあるが、
たいてい操作しているうちに気がつく。しかし、変数スコープに関しては私にはなかなか呪縛を解くことができないような気がするので注意しなければ。

クロスプラットフォーム対応ということだったので、Ubuntu18.4(VMWare)にPowerShell Coreを入れて、WindowsにもCoreを入れてWindowsからつないでみた。Windows PoweShellの中でpwshを起動すると読めない程、勝手にフォントサイズが小さくなってしまい使いにくかった。sshクライアントを起動しても同じような現象が起きるので、sshの設定をうまくしてやると回避できるのかもしれない。

f:id:willwealth:20200210134129p:plain
WindowsからUbuntuにEnter-PSSession
構築した環境の不備によるものなのか、Get-ChildItemの表示ではなぜか日本語のディレクトリ名の表示が変だった。

それにしても、もっと早く本書を読んでいれば不要な苦労をしなくて済んだであろうにと後悔したとともに、パイプラインで利用できるスクリプトのノウハウを蓄積して生産性の向上に役立てていってほしいです。