本文将介绍 PowerShell 中的 PSReadLine 模块,并给出一些实用的配置示例。

本文基于 PowerShell 7.2 LTS 版本,请读者使用 PowerShell 7.2 或更新版本。

官方文档

PSReadLine 模块源起

A bash inspired readline implementation for PowerShell.

PSReadLine 模块是在 Bash 的启发下开发的 PowerShell 版 Readline 实现。

那么,Readline 又是什么呢?

Readline 是一个软件库,可为具有命令行界面(例如 Bash)的交互式程序提供行编辑器和历史记录功能。

PSReadLine 模块功能简介

PSReadLine 模块为 PowerShell 终端带来了强大的命令行编辑器体验。

  • 语法着色
  • 语法错误提示
  • 命令补全
  • 自动保存历史命令
  • 交互式搜索历史命令
  • 智能提示
  • ETC.

用户可以使用 Get-PSReadLineOption 命令获取 PSReadLine 模块的当前设置,亦可使用 Set-PSReadLineOption 修改 PSReadLine 模块的设置。

下文将着重介绍 PSReadLine 模块中命令历史记录相关的功能及配置。

PSReadLine 模块命令历史记录功能

功能简介

PSReadLine 模块维护了一份记录着历史命令的文件,名为 "$($host.Name)_history.txt",一般来说名为 ConsoleHost_history.txt,文件路径为 "$Env:APPDATA\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt"。

PSReadLine 模块会自动过滤敏感内容,任何包含下列内容的命令将不会被记录。

  • password
  • asplaintext
  • token
  • apikey
  • secret

Bash 中的命令历史记录功能

若读者熟悉 Bash Shell 一定知道 Bash 可以通过配置 Bash 变量来修改 Bash 的命令历史记录功能,不熟悉的读者可以查阅官方文档。

例如 HISTCONTROL 变量,该变量有几个取值 ignorespace, ignoredups, erasedups 和 ignoreboth。

若设置 ignorespace,所有以空格开头的命令将不会被写入历史记录。

若设置 ignoredups,所有与上一条历史命令重复的命令将不会被写入历史记录。

若设置 erasedups,所有与当前命令重复的历史命令将被从历史记录中删除并将当前命令写入历史记录。

ignoreboth 则相当于 ignorespace 和 ignoredups 的组合。

一般情况下,Bash 默认将 HISTCONTROL 变量设置为 ignoreboth,这将大大减少命令历史记录中的「噪音」。

在 PowerShell 中模仿 Bash 的历史命令记录策略

那么,如何在 PowerShell 中实现类似于 ignoreboth 的历史命令记录策略呢?这需要些许技巧。

如果想要实现类似于 ignoredups 的效果十分简单,PSReadLine 模块中直接提供了 -HistoryNoDuplicates 配置项,该选项默认为 $False。你可直接执行 (Get-PSReadLineOption).HistoryNoDuplicates = $True 将该配置项启用。

问题在于 ignorespace,PSReadLine 模块并没有提供配置项实现类似的效果,好在 PSReadLine 模块提供了另一个更加强大的配置项 -AddToHistoryHandler。我们可以自定义一个脚本块,用于控制将哪些命令添加到 PSReadLine 历史记录。

该脚本块接受命令行作为输入并返回 $True 或 $False。若返回为 $True 则将该条命令加入历史记录,否则不将其加入历史记录。

持久化 PSReadLine 模块的命令历史记录功能配置

如果直接在 PowerShell 会话中使用 Set-PSReadLineOption 配置 PSReadLine 模块,该会话中的所有配置将在下一个会话中失效,换言之,配置是特定于会话的。

难道我们每次启动 PowerShell 会话都需要手动重新配置一遍吗?我们可以使用 PowerShell 配置文件来持久化配置。

若你不清楚如何创建并使用 PowerShell 配置文件,请参考这篇博文。

打开 PowerShell 配置文件写入以下内容

$options = @{
    HistoryNoDuplicates           = $True
    AddToHistoryHandler           = {
        Param([String]$line)
        return $line[0] -ne ' ' -and $line.Length -gt 5
    }
    HistorySearchCursorMovesToEnd = $True
}

Set-PSReadLineOption @options

你也可以直接下载使用我的 PowerShell 配置文件。

GitHub 仓库地址

如果文章对你有所帮助的话,欢迎给我点个 Star。

其它 PSReadLine 模块功能

本文未提及的功能,读者可自行查阅官方文档

你可以使用 -EditMode 配置项指定命令行编辑模式,例如 Emacs 或 Vi。

如果你习惯使用 Vi 键位的话,你还可以使用 -ViModeChangeHandler 显示 Vi 模式的变更。

function OnViModeChange {
    if ($args[0] -eq 'Command') {
        # Set the cursor to a blinking block.
        Write-Host -NoNewLine "`e[1 q"
    } else {
        # Set the cursor to a blinking line.
        Write-Host -NoNewLine "`e[5 q"
    }
}
Set-PSReadLineOption -ViModeIndicator Script -ViModeChangeHandler $Function:OnViModeChange