如何避免PowerShell中打印ESC字符(U+001b)导致命令停止?
如何避免PowerShell中打印ESC字符(U+001b)导致命令停止?
我来帮你搞定这个问题!你遇到的情况其实是Windows终端对ESC字符的特殊处理导致的——ESC(U+001b)是虚拟终端(VT)控制序列的起始符,不管是旧的Windows Console Host还是新的Windows Terminal,默认都会把它当成终端控制指令的开头,而不是普通的可打印字符,所以输出ESC后终端会一直等待后续的控制字符来组成完整序列,导致命令卡住,必须按Ctrl-C才能终止。
下面给你介绍实用的解决办法,亲测符合你的场景:
方法一:禁用虚拟终端(VT)支持
通过调用Windows API修改控制台模式,让终端把ESC当成普通字符处理。首先你需要定义一个辅助类来调用系统API:
Add-Type -Namespace ConsoleHelper -Name Console -MemberDefinition @' [DllImport("kernel32.dll", SetLastError = true)] public static extern bool GetConsoleMode(IntPtr hConsoleHandle, out uint lpMode); [DllImport("kernel32.dll", SetLastError = true)] public static extern bool SetConsoleMode(IntPtr hConsoleHandle, uint dwMode); [DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr GetStdHandle(int nStdHandle); public static bool EnableVtSupport(bool enable) { IntPtr stdOut = GetStdHandle(-11); // 获取标准输出句柄 if (!GetConsoleMode(stdOut, out uint mode)) return false; const uint ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x0004; if (enable) { mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; } else { mode &= ~ENABLE_VIRTUAL_TERMINAL_PROCESSING; } return SetConsoleMode(stdOut, mode); } '@
定义好之后,调用这个方法禁用VT支持,再输出ESC字符就不会卡住了:
[ConsoleHelper.Console]::EnableVtSupport($false); '{0}' -f [char]27
不同场景的表现说明
- 分开执行命令的情况:如果你先执行禁用VT的命令,再单独执行输出ESC的命令,不管是Windows Console Host还是Windows Terminal都会卡住,所以建议把两个命令放在同一行执行。
- 同一行执行命令:
- Windows Console Host:可以顺利结束,不会卡住;
- Windows Terminal:需要按一下Enter才能结束,但不会一直挂着。
- 写入脚本执行:把命令保存成
.ps1脚本,用powershell -ExecutionPolicy RemoteSigned .\test.ps1执行时:- Windows Console Host:完全正常,顺利结束;
- Windows Terminal:也能正常结束,但可能会出现ESC之后第一个字符丢失的小问题,不过这总比命令卡住强。
方法二:避免直接输出到终端
如果你不需要在终端里看到ESC字符,也可以把它存入变量或者输出到文件,这样终端不会收到ESC指令,自然不会卡住:
# 把ESC字符存入变量 $escChar = [char]27 # 或者输出到文件 "{0}" -f $escChar | Out-File .\esc_output.txt
备注:内容来源于stack exchange,提问作者SATO Yusuke
相关产品推荐
相关产品推荐

