且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

我可以在 powershell read-host 中使用现有变量吗

更新时间:2023-11-10 16:47:46

如果我理解正确的话,您正在寻找两个Read-Host 自 PowerShell 7.1 起:

If I understand correctly, you're looking for two features that are not implemented in Read-Host as of PowerShell 7.1:

  • (a) 使用默认值预填充编辑缓冲区,用户可以按原样接受或修改.

  • (a) Pre-filling the edit buffer with a default value, which the user can either accept as-is or modify.

  • 另一种方法是通过 -Prompt 字符串通知用户,如果他们不输入新的值,将使用什么值,但那样您将无法区分用户选择了默认值还是只是想中止提示(他们可以使用 Ctrl-Ckbd>,但是).
  • The alternative is just to inform the user, via the -Prompt string, what value will be used if they don't enter a new one, but that way you won't be able to distinguish between the user choosing the default value or simply wanting to abort the prompt (which they could do with Ctrl-C, however).

(b) 保留用户输入值的持久历史,记住(至少)最近输入的值,跨 PowerShell 会话.

注意:Read-Host 目前是最基本的.为 PowerShell 本身提供丰富的交互式命令行编辑体验的模块是 PSReadLine,如果其功能(包括持久历史记录和修改编辑缓冲区)可供用户使用,那就太好了用于通用提示的代码 - 参见 GitHub 提案 #881.
通过 Read-Host 实现这些增强功能可能是***的选择,或者至少可以在那里实现预填充编辑缓冲区的功能:请参阅 GitHub 提案 #14013.

Note: Read-Host is currently bare-bones. The module that provides the rich interactive command-line editing experience for PowerShell itself is PSReadLine, and would be great if its features, which include a persistent history and modifying the edit buffer, could be made available to user code for general-purpose prompting - see GitHub proposal #881.
Surfacing such enhancements via Read-Host is probably the best option, or at least the ability to prefill the edit buffer could be implemented there: see GitHub proposal #14013.

请参阅 - 有限 - 以下 (a) 和 (b) 的自定义实现.

See - limited - custom implementations of (a) and (b) below.

(a) 目前仅可能通过解决方法,并且仅在 Windows 上,在 常规控制台窗口Windows 中终端(它在过时 PowerShell ISE 谢谢,CFou.,并且在 Visual Studio Code 的集成终端中,它只有在启动调试会话后立即单击将焦点放在它上时才有效):

(a) is currently only possibly via a workaround, and only on Windows, both in regular console windows and Windows Terminal (it does not work (reliably enough) in the obsolescent PowerShell ISE Thanks, CFou., and in Visual Studio Code's integrated terminal it only works if you place the focus on it by clicking immediately after launching a debug session):

# The (default) value to pre-fill the Read-Host buffer with.
$myVar = 'This is a default value.'

# Workaround: Send the edit-buffer contents as *keystrokes*
# !! This is not 100% reliable as characters may get dropped, so we send
# !! multiple no-op keys first (ESC), which usually works.
(New-Object -ComObject WScript.Shell).SendKeys(
  '{ESC}' * 10 + ($myVar -replace '[+%^(){}]', '{$&}')
)

$myVar = Read-Host 'Enter a value'  # Should display prompt with value of $myVar

注意:-replace 操作对于转义默认值中的字符是必要的,否则对.SendKeys()有特殊意义.

Note: The -replace operation is necessary to escape characters in the default value that would otherwise have special meaning to .SendKeys().

(b) 要求你实现自己的持久化机制,明显的选择是使用文件:

(b) requires you to implement your own persistence mechanism, and the obvious choice is to use a file:

这里有一个简单的方法,它只存储最近输入的值.

Here's a simplistic approach that only stores the most recent value entered.

  • 每个提示支持多个历史值也将支持Read-Host中的recall,例如使用向上箭头和向下箭头循环浏览历史,自 PowerShell 7.1 起支持.
  • Supporting multiple historic values per prompt would also support for recall in Read-Host, such as as using up-arrow and down-arrow to cycle through the history, which is not supported as of PowerShell 7.1.
# Choose a location for the history file.
$historyFile = "$HOME/.rhhistory"

# Read the history file (which uses JSON), if it exists yet.
$history = Get-Content -Raw -ErrorAction Ignore $historyFile | ConvertFrom-Json
$defaultValue = 'This is a default value.'

# Get the 'myVar' entry, if it exists, otherwise create it and use the default value.
$myVar = 
  if (-not $history) { # no file yet; create the object to serialize to JSON later
    $history = [pscustomobject] @{ myVar = '' }
    $defaultValue
  } elseif (-not $history.myVar) { # file exists, but has no 'myVar' entry; add it.
    $history | Add-Member -Force myVar ''
    $defaultValue
  } else {  # return the most recently entered value.
    $history.myVar
  }

# Prompt the user.
(New-Object -ComObject WScript.Shell).SendKeys(
  '{ESC}' * 10 + ($myVar -replace '[+%^(){}]', '{$&}')
)
$myVar = Read-Host 'Enter a value'

# Validate the value...

# Update the history file with the value just entered.
$history.myVar = $myVar
$history | ConvertTo-Json > $historyFile