窓辺の小石 第209回 PSターミナル・エクスペリメント

2025年3月28日(金)13時59分 マイナビニュース


PowerShell、Windows PowerShell(以後PowerShellと表記)に搭載されているPSReadLineは、キーボードショートカットに、PSReadLineの機能(メソッドや関数)を割り当てることができる。このとき、スクリプトブロックで割り当てを行うことができるので、いわゆるマクロを作ることができる。
このとき利用できる機能に関しては、「about_PSReadLine_Functions(PowerShell 7.5)」または「about_PSReadLine_Functions - PowerShell(Windows PowerShell 5.1)」を参照されたい。
キーボードショートカットの追加には、Set-PSReadLineKeyHandlerで行う。コマンド構文は、
Set-PSReadLineKeyHandler
[-ScriptBlock]
[-BriefDescription ]
[-Description ]
[-Chord]
[-ViMode ]
[]
となっている。ここで、「-BriefDescription 」は、Get-PSReadlineKeyHandlerで「Function」プロパティとして表示される文字列。「[-Description ]」は、「Description」として表示される文字列だ。
具体的にマクロを定義してみよう。PowerShellでは、コマンドを実行したあと、特定のプロパティだけを取り出したい場合がある。特にワンライナーの一部で使う場合など、コマンド全体をカッコでくくって、ピリオドでプロパティ名を指定する記述を使う。つまり「command」を「(command).Property」という形式にすることが少なくない。このとき、行の先頭に開き括弧を入れる必要があり、少し面倒くさい。これをマクロで自動化してみよう。
仕様としては、コマンドラインの現在のカーソル位置に「).」を入れ、行の先頭に「(」を入れる。行末ではなくカーソル位置としたのは、後続のコマンドラインがあることを考慮したからだ。選択範囲があるなら、その先頭に「(」を入れ、その末尾に「).」を入れる。キー定義は、リスト01のようになる。
■リスト01
Set-PSReadLineKeyHandler -Chord Ctrl+Shift+b -BriefDescription "Macro" -Description "括弧で囲んでピリオドを付けるV4" -ScriptBlock {
$start = $null
$length=$null
[Microsoft.PowerShell.PSConsoleReadLine]::GetSelectionState([ref]$start,[ref]$length)
if( $start -eq -1) {
$line = $null
$cursor = $null
[Microsoft.PowerShell.PSConsoleReadLine]::GetBufferState([ref]$line, [ref]$cursor)
[Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition(0)
[Microsoft.PowerShell.PSConsoleReadLine]::Insert('(')
[Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($cursor+1)
} else {
[Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($start)
[Microsoft.PowerShell.PSConsoleReadLine]::Insert('(')
[Microsoft.PowerShell.PSConsoleReadLine]::SetCursorPosition($start+$length+1)
}
[Microsoft.PowerShell.PSConsoleReadLine]::Insert(').')
}
ここでは、キーボードショートカットとしてWindowsモード、Emacsモードのどちらでも衝突しない「Ctrl+Shift+b」を選んだ。ただし、このキーは、Get-PSReadLineKeyHandlerでは、「Ctrl+B」と表示されることに注意されたい。Get-PSReadLineKeyHandlerでは「Shift+b」を「B」と表し、Ctrl+bとCtrl+Bが区別されている。
スクリプトブロックを簡単に解説しよう。先頭にあるのは、3行目のGetSelectionStateで使うための変数。引数に指定した変数に値が入って戻ってくる。この関数で最初の引数($start)は、選択範囲の開始位置を示すが、選択範囲がない場合には、-1が入る。5行目のif文はこれを判定している。
選択範囲がない場合、先頭に括弧を入れる。そのための処理が次の行から。GetBufferStateで現在のカーソル位置を取得している。
次の「SetCursorPosition(0)」で行(複数行可)の先頭にカーソルを移動させる。「Insert('(')」で先頭に開き括弧を挿入し、「SetCursorPosition($cursor+1)」で元の位置(先頭に括弧を挿入したので+1で1文字右に移動している)に戻る。
「else」の後は選択範囲がある場合の処理だ。ここでは選択範囲の先頭に「Insert('(')」で開き括弧を挿入し、SetCursorPosition($start+$length+1)で選択範囲の直後にカーソルを戻している。
どちらの場合も最後に「Insert(').')」で閉じ括弧とピリオドを付けている。
今回のタイトルネタは、ロバート・J・ソーヤー(Robert J. Sawyer)の「ターミナル・エクスペリメント」(ハヤカワ文庫SF。原題The Terminal Experiment,1995年)である。この作品、雑誌に掲載されていたときには、「Hobson's Choice」という題名だった。Hobson's Choiceとは、選択肢といいながら、受け入れるか、受け入れないかを選ばねばならず、受け入れないことは望ましくないため、実際には1つしか選択できない「選択肢」のことだ。Windowsにはcmd.exeや様々な言語のREPL、さらにはWSLのbashなど「シェル」や「シェル」らしいプログラムが多数ある。しかし、実際にシステム管理などのシェルとして使えるのはPowerShellだけしかない。

マイナビニュース

「石」をもっと詳しく

「石」のニュース

「石」のニュース

トピックス

x
BIGLOBE
トップへ