打印 ESCAPE (U+001b) 将停止 PowerShell 中的命令

问题描述 投票:0回答:1

当我尝试列出所有 ASCII 字符及其 Unicode 类别时,我发现打印控制字符

ESCAPE
(
U+001b
) 会停止命令。

例如,只有输入

Ctrl-C
27
0x1b
的十进制形式),以下命令才会返回:

PS C:\> "{0}" -F ([Char]27)

问题

有什么办法可以防止在命令中打印

U+001b
时停止命令吗?

powershell escaping
1个回答
0
投票

问题PowerShell自动为自身启用VT(虚拟终端)支持,这意味着ESCAPE字符(U+001B

),即Unicode代码点
0x1b(十进制
)的字符27
)似乎总是被解释为
 作为 VT (ANSI) 转义序列的开始
: 因此,

  • ESCAPE

    alone是一个不完整转义序列,因此会导致表面上挂起,仅在Windows上(在Unix类平台上,根本就没有可见输出)。

  • 在 Windows 上实际发生的情况是,不完整的转义序列导致下一个 PowerShell
  • 提示不渲染

    ,但后续命令输入被接受并可以照常提交,但有一个例外:按 Enter alone不起作用,但如果您提交一个 space,然后按 Enter,则会执行无操作命令,并且提示符将恢复正常。 请注意,这同样适用于 Windows 终端中的常规控制台窗口和会话。

解决方法

注意:以下假设您想要打印 ESCAPE 字符,就像 VT 支持被disabled

一样,即

当该符号被解释为

 右侧可打印字符 
而不是
控制字符 的可视化时,它是以下 Unicode 字符: (向左箭头,
U+2190

    选项 A
  • :只需

    用向左箭头替换实际的 ESCAPE 字符,以实现 显示输出 $c = [char] 0x1b '{0}' -f ($c -replace [char] 0x1b, [char] 0x2190)

    虽然这可以避免“挂起”,但它具有以下
    限制
    • 它改变了你的脚本输出的数据
        (尽管这可能并不重要)
      • 要可视化 other
      • 控制字符,就好像 VT 支持已关闭一样,您也必须为它们提供类似的替换。
  • 选项 B
  • 暂时禁用 VT 支持 这是更全面的解决方案,但有以下

    限制
      • 需要对 WinAPI 进行 P/Invoke 调用
      • ,这又需要对 C# 代码进行临时编译,这会导致

        每个会话一次的性能损失

        如果您在脚本中明确重新打开 VT 支持(如下所示),则会尝试“间接”打印到控制台,例如通过将脚本的调用括在
      • (...)
      • 中或通过管道传输到

        Write-HostOut-Host

        Write-Output
        ,将再次出现“挂起”。
        另一种方法是让 PowerShell
        自动
        重新启用它,
        下次它在交互式会话中打印提示符时

      # Compile a helper type with P/Invoke declarations for enabling / disabling VT support. # Note: This incurs a once-per-session peformance penalty. $consoleHelper = Add-Type -PassThru -Namespace "NS$PID" -Name ConsoleHelper -MemberDefinition @' [DllImport("kernel32.dll", SetLastError=true)] static extern bool SetConsoleMode(IntPtr hConsoleHandle, int mode); [DllImport("kernel32.dll", SetLastError=true)] static extern bool GetConsoleMode(IntPtr handle, out int mode); [DllImport("kernel32.dll", SetLastError=true)] static extern IntPtr GetStdHandle(int handle); public static void EnableVtSupport(bool enable = true) { IntPtr outHandle = GetStdHandle(-11); // -11 == STD_OUTPUT_HANDLE int mode; GetConsoleMode(outHandle, out mode); SetConsoleMode(outHandle, enable ? (mode | 0x4) : (mode & ~0x4)); // 0x4 == ENABLE_VIRTUAL_TERMINAL_PROCESSING } '@ # Temporarily turn off VT support. $consoleHelper::EnableVtSupport($false) # This now does NOT cause the "hang" and prints "←" instead. '{0}' -f [char] 27 # Re-enable it (see caveat above). $consoleHelper::EnableVtSupport($true) # Verify that VT support is back on: the word "green" should print in green. # Note: In PS 7+ you could use `e inside "..." to produce ESCAPE chars: # "It ain't easy being `e[32mgreen`e[m." 'It ain''t easy being {0}[32mgreen{0}[m.' -f [char] 27
© www.soinside.com 2019 - 2024. All rights reserved.