🔌

powershell 意外とよい

2023/12/15に公開

古の powershell 本を発掘して再び使い始めた。

https://www.sbcr.jp/product/4797337362/

powershell-1.0 の頃の本。

  • powershell-7.4
  • wezterm

なかなかいい感じに設定できて、
普通に history search や completion の効く快適な shell になった。

以降、基本的に $profile に設定します。

https://learn.microsoft.com/ja-jp/powershell/scripting/learn/shell/creating-profiles?view=powershell-7.4

> pwsh
PS1> code $profile # VSCODE で powershell の設定を開く

# POWERSHELL 拡張を入れて lsp, syntaxhighlight, formatter を手に入れる

readline を設定する

https://learn.microsoft.com/en-us/powershell/module/psreadline/about/about_psreadline_functions?view=powershell-7.4

# Set-PSReadLineOption -EditMode emacs # たぶん、まとめて設定されるので使う場合は最初に。
# 個別に設定
Set-PSReadlineKeyHandler -Key 'Ctrl+u' -Function BackwardDeleteLine
Set-PSReadlineKeyHandler -Key 'Ctrl+b' -Function BackwardChar
Set-PSReadlineKeyHandler -Key 'Ctrl+f' -Function ForwardChar
Set-PSReadlineKeyHandler -Key 'Ctrl+d' -Function DeleteCharOrExit # ctrl-d exit する
Set-PSReadlineKeyHandler -Key 'Ctrl+h' -Function BackwardDeleteChar
Set-PSReadlineKeyHandler -Key 'Ctrl+p' -Function HistorySearchBackward # history
Set-PSReadlineKeyHandler -Key 'Ctrl+n' -Function HistorySearchForward # history
Set-PSReadlineKeyHandler -Key 'Ctrl+a' -Function BeginningOfLine
Set-PSReadlineKeyHandler -Key 'Ctrl+e' -Function EndOfLine
Set-PSReadlineKeyHandler -Key 'Ctrl+m' -Function AcceptLine # ctrl+M で enter
Set-PSReadlineKeyHandler -Key 'Ctrl+k' -Function ForwardDeleteLine
# ctrl + [
# [System.Console]::ReadKey()
Set-PSReadlineKeyHandler -Key 'Ctrl+Oem4' -Function RevertLine # ctrl+[ で escape. vim 的な挙動

わりと bash っぽい挙動にできた。
これが最重要であとは好みの問題です。

予測補完は PSReadline に含まれています。

https://learn.microsoft.com/ja-jp/powershell/scripting/learn/shell/using-predictors?view=powershell-7.4

alias 全部消す

cp, mv, rm 等が、同名のコマンドと似て非なるもので、むしろ分かりにくいような気がするので
きれいさっぱり消してしまった。
あと powershell に固有の gci, sal などの短い名前も覚えて慣れてしまうと逆によくない気がした。powershell の language-server が alias 名使うのは止めておけと諭してくれます。
さすがに cd など、必要なものを改めて設定した。

Remove-Item  alias:* -force # 全消し

# cd はさすがに要る
Set-Alias cd Set-Location

# 引数付きは関数で
# rm -rf
function rmrf()
{
  Remove-Item -Recurse -Force $args
}

# which command の代わり。
function has($cmdname)
{
  try
  {
    Get-Command $cmdname -ErrorAction Stop | Select-Object -ExpandProperty Definition
    return $true
  } catch
  {
    return $false;
  }
}

# `%` や `?` も alias
Set-Alias % ForEach-Object
Set-Alias ? Where-Object

普通に Get-Item, Get-ChildItem, Move-Item, Remove-Item 等の組み込みコマンドレットを直接使っています。よく使うものを後付けで少しずつ alias や 関数で短い名前を付ける感じ。

module 厳選

まず、posh-git の初期化が遅いので使うのを中止しました。
複数の shell を次々に開くタイプの場合は、 posh-git はお勧めできない。
なんか適当にスクリプトで手作りするとよいと思う。
Module は起動が遅くならない程度に厳選した方がよさそう。

-Verbose をつけることで字の出るタイミングで固まり具合がある程度わかる。

Import-Module -Verbose posh-git

計測するときはこちら。

https://qiita.com/SAITO_Keita/items/fc385bbc6e3025686d8b

module uninstall

PSReadLine が 2.2.6 で古いままになっていた。
たぶん、powershell-7.4 install 時にどこかで使われていてモジュールの更新ができなかった。

しかし、Uninstall-Module PSReadline はモジュール使用中としてはじかれた。

cmd.exe から試みる。

> pwsh.exe -NoProfile
PS1> Uninstall-Module PSReadline # まだはじかれる。キーボードたたいた時にロードされてそう

cmd.exe からこうする。

> pwsh.exe -NoProfile -Command Uninstall-Module PSReadLine

新しくなった。

> Get-Module PSReadLine

ModuleType Version    PreRelease Name                                ExportedCommands
---------- -------    ---------- ----                                ----------------
Script     2.3.4                 PSReadLine                          {Get-PSReadLineKeyHandler, Get-PSReadLineOption, Remove…

powershell スクリプトの気になったところ

わりと癖が強め。

if文 関数の戻り値

if文の std-out への出力はもみ消しぽい。使える
std-err は出る。
何が $true で $false かはよくわからない。
$false 条件を調べる必要がある。

スクリプトでは戻り値を省略すると null で false と評価されることが多いが、
powershell では $true ぽい。
$false を返す方が特殊なので注意する。
$? だと考える。

配列のスライス構文

$a[1..$a.length-1] # 長さ1のとき空にならない。これは使えない

$a[1..] # これはエラー。不許可。
$a[1..-1] # これも意図したものにならない

パイプに流れる型

CmdLet からは Object[] が流れてくることが多い(C# の Object)。
外部コマンドからは string[] が1行ずつ流れてくる。
ただし、1行しかない場合は string だった。
同じコマンドで行数が増減する場合は対応する必要がある。

$lines = @(git status --porcelain --branch) # 常に配列

() で call

shell なので関数呼び出しではなくコマンド実行と考える。

cmd (cmd2 arg) # 入れ子を実行する。

cmd arg # 行頭、= や | の次など、特定の条件で()が省略できるぽい。

$Variable:Name

https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_providers?view=powershell-7.4

変数はプロバイダーに所属するぽい。
プロバイダーを省略すると Variable プロバイダーが使われる。
${provider:name} でアクセスできる。

$Variable:PROFILE # $PROFILE。{} はわりと省略できる

$env:USERPROFILE # 環境変数

Get-Item とか Item 系の CmdLet が使える。

${C:Program Files} # ファイルパスもプロバイダーなので Get-ChildItem など同じコマンド。

文字列中の変数展開と関数call

$dotfiles = "${env:USERPROFILE}\dotfiles" # ${}使える

$now = "now => $(Get-Date)" # $()で呼び出し

などなど。
細かいルールが powershell 固有で困るのだが、
language-server と syntaxhighlight と formatter の助けがあるならば、
まぁいいかなぁという感じはする。
変さでは bash もそんなに変わらない。

nvim

nvim でも快適に edit できております。

  require("lspconfig").powershell_es.setup {
    bundle_path = vim.env.HOME .. "/.vscode/extensions/ms-vscode.powershell-2023.8.0/modules",    
    -- WSL の場合
    -- bundle_path = vim.env.HOME .. "/.vscode-server/extensions/ms-vscode.powershell-2023.8.0/modules",
    
  }

Discussion