DATAセクション

配列やハッシュテーブルのようにデータを格納する方法ではないが、PowerShell Coreのスクリプトを読む上で欠かすことのできない「DATAセクション」という機能を紹介しておく。

DATAセクションは必ずしも使わなければならない機能ではないが、国際化対応しているPowerShell Coreスクリプトなどで使われている方法なので、 スクリプトを読むためにどういったものであるかを理解しておく必要がある。

DATAセクションはPowerShell Coreにおいてデータを文字列として記述することを可能にする機能。スクリプトにおいてもロジックとデータを分離することはコードの読みやすさや理解しやすさを向上させる点において意味がある。

PowerShell Coreでは主にテキストメッセージなどを国際化対応する方法としてこの機能が使われている。

DATAセクションの利用例

まず、DATAセクションを利用してどのようにPowerShell Coreスクリプトを記述するのか見てみよう。

次のPowerShell CoreスクリプトはmacOSで動作するように書いたPowerShell Coreのスクリプトだ。『DATA {』から『}』までがDATAセクションになっており、結果が変数$msgに代入されるというコードになっている。

SysExists.ps1 - DATAセクションを使ったPowerShell Coreスクリプトの例

#!/usr/local/bin/pwsh

$msg = DATA {
    # Exit status codes for system programs
    ConvertFrom-StringData @'
        OK = Successful termination
        USAGE = Command line usage error
        DATAERR = Data format error
        NOINPUT = Cannot open input
        NOUSER = Addressee unknown
        NOHOST = Host name unknown
        UNAVAILABLE = Service unavailable
        SOFTWARE = Internal software error
        OSERR = System error
        OSFILE = Critical OS file missing
        CANTCREAT = Can't create output file
        IOERR = Input/output error
        TEMPFAIL = Temp failure
        PROTOCOL = Remote error in protocol
        NOPERM = Permission denied
        CONFIG = Configuration error
'@
}

$msg

DATAセクションを使う場合にはConvertFrom-StringDataコマンドレットが欠かせない。ConvertFrom-StringDataコマンドレットは文字列として記述された鍵と値の組み合わせをハッシュテーブルに変換する処理を行う。

つまり、上記のように記述することで、文字列として書いたものをハッシュテーブルとして$msgに代入することができる。

このスクリプトを実行すると次のようになる。

SysExists_en.ps1の実行例

/Users/daichi/tmp$ ./SysExists_en.ps1

Name                           Value
----                           -----
SOFTWARE                       Internal software error
NOUSER                         Addressee unknown
USAGE                          Command line usage error
PROTOCOL                       Remote error in protocol
IOERR                          Input/output error
TEMPFAIL                       Temp failure
OSERR                          System error
OSFILE                         Critical OS file missing
NOHOST                         Host name unknown
CONFIG                         Configuration error
NOINPUT                        Cannot open input
OK                             Successful termination
DATAERR                        Data format error
CANTCREAT                      Can't create output file
UNAVAILABLE                    Service unavailable
NOPERM                         Permission denied


/Users/daichi/tmp$

DATAセクションにはこれ以外の記述も含めることができる。詳しい使い方はいずれ取り上げるとして、DATAセクションを利用することでこんな風にデータをロジックから分離してまとめて書けるようになる、ということを覚えておいてもらえればと思う。

DATAセクションの利用例 - 国際化するための使い方

PowerShell Coreでは実際にはDATAセクションは国際化などの用途で使われるのだが、その例を見てみよう。まず、先ほどのスクリプトを次のように変更する。

SysExists.ps1 - 国際化対応版

#!/usr/local/bin/pwsh

Import-LocalizedData -BindingVariable msg

$msg

Import-LocalizedDataコマンドレットは国際化スクリプトを作成する際には欠かすことのできないコマンドレットで、決められたディレクトおよびファイル名で配置された国際化向けファイルからデータを読み取って変数に代入するといった処理を行ってくれる。よくわからないうちはこういう書き方をするものだと思っておけばよいと思う。

国際化データは次のような感じで決められたディレクトリに決められた名前で配置する。SysExists.ps1というファイル名にしてあるので、国際化対応の方のファイル名はSysExists.psd1とする。

そしてロケールごとにディレクトリを作成し、その下にSysExists.psd1というファイル名のデータファイルを置く。構造を見ると次のようになる。

国際化スクリプトの配置例

/Users/daichi/tmp$ tree
.
├── SysExists.ps1
├── en-US
│   └── SysExists.psd1
└── ja-JP
    └── SysExists.psd1

2 directories, 3 files
/Users/daichi/tmp$

国際化スクリプトの中身は、例えば次のようになる。

英語用データファイル - en-US/SysExists.psd1

ConvertFrom-StringData @'
    OK = Successful termination
    USAGE = Command line usage error
    DATAERR = Data format error
    NOINPUT = Cannot open input
    NOUSER = Addressee unknown
    NOHOST = Host name unknown
    UNAVAILABLE = Service unavailable
    SOFTWARE = Internal software error
    OSERR = System error
    OSFILE = Critical OS file missing
    CANTCREAT = Can't create output file
    IOERR = Input/output error
    TEMPFAIL = Temp failure
    PROTOCOL = Remote error in protocol
    NOPERM = Permission denied
    CONFIG = Configuration error
'@

日本語用データファイル - ja-JP/SysExists.psd1

ConvertFrom-StringData @'
    OK = 正常終了
    USAGE = コマンドラインエラー
    DATAERR = データフォーマットエラー
    NOINPUT = インプットオープン不可能
    NOUSER = 不明アドレス
    NOHOST = 不明ホスト名
    UNAVAILABLE = サービス不在
    SOFTWARE = 内部ソフトウェアエラー
    OSERR = システムエラー
    OSFILE = OS関連ファイル不在
    CANTCREAT = 出力ファイル作成不可能
    IOERR = 入出力エラー
    TEMPFAIL = 一時的な失敗
    PROTOCOL = プロトコルにおけるリモートエラー
    NOPERM = 不正パーミッション
    CONFIG = 設定エラー
'@

日本語環境であれば日本語のデータファイルの中身が、英語環境であれば英語のデータファイルの中身が使われるという仕組みになっている。

例えば次のように環境変数LANGを設定してSysExists.ps1を実行すれば、英語データが使われる。

英語データが使われるケース

/Users/daichi/tmp$ env LANG=C ./SysExists.ps1

Name                           Value
----                           -----
TEMPFAIL                       Temp failure
SOFTWARE                       Internal software error
UNAVAILABLE                    Service unavailable
USAGE                          Command line usage error
NOINPUT                        Cannot open input
NOUSER                         Addressee unknown
CONFIG                         Configuration error
NOPERM                         Permission denied
PROTOCOL                       Remote error in protocol
OSERR                          System error
NOHOST                         Host name unknown
CANTCREAT                      Can't create output file
DATAERR                        Data format error
IOERR                          Input/output error
OSFILE                         Critical OS file missing
OK                             Successful termination


/Users/daichi/tmp$

環境変数LANGをja_JP.UTF-8に設定すれば、次のように日本語データが使われるようになる。

日本語データが使われるケース

/Users/daichi/tmp$ env LANG=ja_JP.UTF-8 ./SysExists.ps1

Name                           Value
----                           -----
NOPERM                         不正パーミッション
SOFTWARE                       内部ソフトウェアエラー
UNAVAILABLE                    サービス不在
CONFIG                         設定エラー
NOUSER                         不明アドレス
OSERR                          システムエラー
OK                             正常終了
OSFILE                         OS関連ファイル不在
PROTOCOL                       プロトコルにおけるリモートエラー
CANTCREAT                      出力ファイル作成不可能
NOHOST                         不明ホスト名
NOINPUT                        インプットオープン不可能
IOERR                          入出力エラー
USAGE                          コマンドラインエラー
TEMPFAIL                       一時的な失敗
DATAERR                        データフォーマットエラー


/Users/daichi/tmp$

環境変数LANGをen_US.UTF-8にすると次のように英語データが使われるようになる。

英語データが使われるケースその2

/Users/daichi/tmp$ env LANG=en_US.UTF-8 ./SysExists.ps1

Name                           Value
----                           -----
NOHOST                         Host name unknown
CANTCREAT                      Can't create output file
TEMPFAIL                       Temp failure
SOFTWARE                       Internal software error
OSERR                          System error
OSFILE                         Critical OS file missing
USAGE                          Command line usage error
IOERR                          Input/output error
DATAERR                        Data format error
NOPERM                         Permission denied
PROTOCOL                       Remote error in protocol
OK                             Successful termination
NOUSER                         Addressee unknown
NOINPUT                        Cannot open input
CONFIG                         Configuration error
UNAVAILABLE                    Service unavailable


/Users/daichi/tmp$

こんな感じでデータファイルを用意してあげれば、それに応じてデータが使われるようになる仕組みになっている。

PowerShell Coreスクリプトについてわからない方も、今回はひとまず、データを書く方法にDATAセクションというやり方があり、この機能はスクリプトを国際化するといった目的で使われる、ということを把握しておいてほしい。解説が進むにつれ、ピンとくることがあるはずだ。

参考資料