PowerShell スクリプトで気をつけたいこと その2
開発部の本橋です。先日投稿した PowerShell スクリプトで気をつけたいこと の続編です。
親スコープの変数を子スコープのブロックから書き換えたい
スクリプト言語にはよくある話ですが、親スコープに存在する変数を書き換える際に気をつける必要があります。
そもそも PowerShell のスコープには次の5種類があります。*1
- Global
- その名の通りグローバルスコープです。スクリプトファイル外からでも参照可能です。
- Local
- カレントのスコープです。子スコープからも参照可能です。
- Script
- 同一スクリプトファイルの中でのみ参照可能です。
- Private
- カレントスコープでのみ参照可能です。
- Numbered Scopes
- カレントブロックからの相対数を指定してスコープを参照します。
何も考えずに変数を定義すると Local
スコープになります。以下はうまくいかない例です。
# このスコープに変数 $a を定義 (Local スコープ) $a = 'A' # スクリプトブロックを定義して子スコープを作る $fn = { Write-Host $a # ==> A # 親スコープの変数 $a を書き換えたつもりだが、 # このスコープに変数 $a を定義 (Local スコープ) $a = 'B' Write-Host $a # ==> B } # スクリプトブロックを呼び出し & $fn # このスコープの $a は書き換わっていない Write-Host $a # ==> A
$a
をスクリプトブロックの中で書き換えたつもりでも、スクリプトブロックを抜けると $a
はもとに戻ってしまいます。コメントにも書きましたが、$fn
の Local
スコープに $a
を定義してしまっているためです。
この場合、スコープを指定して $a
に代入します。
# このスコープに変数 $a を定義 (Local スコープ) $a = 'A' # スクリプトブロックを定義して子スコープを作る $fn = { Write-Host $a # ==> A # 1つ上のスコープを指定して変数 $a を書き換える Set-Valiable -Name a -Scope 1 -Value 'B' # もしくは Script スコープの変数 $a を定義する #$script:a = 'B' Write-Host $a # ==> B } # スクリプトブロックを呼び出し & $fn # $a は書き換わっている Write-Host $a # ==> B
Set-Variable
コマンドレットで一つ上のスコープを指定して変数の値を書き換えてあげればうまくいきます。また、上記コメント中に書いたように $script:a = 'B'
とすると Script
スコープの変数に代入する形になります。意図しない上書きをしてしまう場合があるので気をつけましょう。