在命令提示符中使用 UTF-8 编码 (CHCP 65001) / Windows Powershell (Windows 10)

Using UTF-8 Encoding (CHCP 65001) in Command Prompt / Windows Powershell (Windows 10)

一段时间以来,我一直在命令提示符和 Windows Powershell 中强制使用 chcp 65001,但从 SO 和其他几个社区的问答帖子来看,它 seems like a dangerous and inefficient solution . Microsoft 是否提供 chcp 65001 的改进/完整替代方案,无需手动更改注册表即可永久保存?如果没有,将来是否有在 Windows CLI 中支持 UTF-8 的公开宣布的时间表或议程?

我个人一直在使用 chcp 949 来支持韩语字符,但是反斜杠 \ 和 incorrect/incomprehensible 的奇怪显示在几个应用程序中显示 (像 Neovim),以及 不是 韩语的字符不受 949 的支持,最近似乎成为一个更严重的问题。

您可以将命令 chcp 65001 放入您的 Powershell 配置文件中,当您打开 Powershell 时,它会自动 运行 它。但是,这对 cmd.exe.

没有任何作用

Microsoft 目前正在开发一种改进的终端,它将完全支持 Unicode。是open source, and if you're using Windows 10 Version 1903 or later, you can already download a preview version.

或者,您可以使用 third-party 终端仿真器,例如 Terminus

注:

  • 这个答案展示了如何将字符编码在Windows控制台中切换为
    UTF-8(代码页65001),以便shellcmd.exe和PowerShell正确编码和解码 字符(文本)在与外部(控制台)程序通信时完整的Unicode支持,在cmd.exe 也适用于文件 I/O.[1]

  • 相比之下,如果您关心的是 Unicode 字符 rendering 的限制的单独方面控制台 windows,请参阅 的中间和底部部分,其中也讨论了替代控制台(终端)应用程序。


Does Microsoft provide an improved / complete alternative to chcp 65001 that can be saved permanently without manual alteration of the Registry?

从(至少)Windows 10,版本 1903 开始​​,您可以选择 设置 系统语言环境non-Unicode 程序的语言)到 UTF-8,但 功能仍然 在撰写本文时处于测试阶段

要激活它:

  • 运行 intl.cpl(在控制面板中打开区域设置)
  • 按照下面屏幕截图中的说明进行操作。

  • 设置 both 系统的活动 OEM ANSI 代码页 65001,UTF-8 代码页,因此 (a) 使所有未来的 console windows 使用 OEM 代码页,默认为 UTF-8(就好像 chcp 65001 已经在 cmd.exe window 中执行过一样)并且 (b) 也使 legacy,non-Unicode GUI-子系统应用程序,(除其他外)使用 ANSI 代码页,使用 UTF-8。

    • 注意事项:

      • 如果您使用 Windows PowerShell,这也会使 Get-ContentSet-Content 和其他上下文,其中 Windows PowerShell 默认为系统的活动 ANSI 代码页,特别是 阅读 源代码 来自 BOM-less 文件默认为 UTF-8(PowerShell Core (v6+) 始终如此)。这意味着,在没有 -Encoding 参数的情况下, BOM-less 属于 ANSI-encoded 的文件(这在历史上很常见)将被误读,而使用 Set-Content 创建的文件将是 UTF-8 而不是 ANSI-encoded.

      • [已在 PowerShell 7.1 中修复] 至少到 PowerShell 7.0,a bug在底层 .NET 版本 (.NET Core 3.1) 中导致 PowerShell follow-on 错误 :UTF-8 BOM 意外地添加到发送到外部的数据通过 stdin 进行处理(无论您将 $OutputEncoding 设置为什么),特别是 中断 Start-Job - 参见 this GitHub issue.

      • 并非所有字体都使用 Unicode,所以选择 TT (TrueType) 字体,但即使它们通常只支持所有字体的 子集 characters,因此您可能需要尝试使用特定字体以查看是否显示了您关心的所有字符 - 有关详细信息,请参阅 ,其中还讨论了具有更好 Unicode 呈现的替代控制台(终端)应用程序支持。

      • 正如 eryksun 指出的那样,不“使用”UTF-8 的旧控制台应用程序将限于 ASCII-only输入 并在尝试输出(7 位)ASCII 范围 之外的字符时将产生 不正确的输出 。 (在过时的 Windows 7 及以下版本中,程序甚至可能 崩溃 )。
        如果 运行ning 遗留控制台应用程序对您很重要,请参阅评论中 eryksun 的建议。

  • 但是,对于Windows PowerShell,即不够:

    • 您还必须 $OutputEncoding 首选项变量也设置为 UTF-8$OutputEncoding = [System.Text.UTF8Encoding]::new()[2];将该命令添加到您的 $PROFILE(仅限当前用户)或 $PROFILE.AllUsersCurrentHost(所有用户)文件中是最简单的。
    • 幸运的是,在 PowerShell Core 中不再需要这样做,它在内部始终默认为 BOM-less UTF-8。

如果将 系统区域设置设置为 UTF-8 在您的环境中不是选项,请使用启动命令改为:

注意:上面提到的关于遗留控制台应用程序的警告同样适用于此。如果 运行ning 遗留控制台应用程序对您很重要,请参阅评论中 eryksun 的建议。

  • 对于 PowerShell(两个版本),将以下行添加到您的 $PROFILE(仅限当前用户)或 $PROFILE.AllUsersCurrentHost ( all users) 文件,相当于 chcp 65001,辅以设置首选项变量 $OutputEncoding 以指示 PowerShell 通过 p 向外部程序发送数据UTF-8 中的 peline:

    • 请注意,从 内部 运行ning chcp 65001 一个 PowerShell 会话 有效,因为 .NET在启动时缓存控制台的输出编码,并且不知道以后使用 chcp 所做的更改;此外,如前所述,Windows PowerShell 需要设置 $OutputEncoding - 有关详细信息,请参阅
$OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding
  • 例如,这里有一个 quick-and-dirty 方法,可以通过编程将此行添加到 $PROFILE
'$OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding' + [Environment]::Newline + (Get-Content -Raw $PROFILE -ErrorAction SilentlyContinue) | Set-Content -Encoding utf8 $PROFILE
  • 对于cmd.exe,通过注册表定义一个auto-run命令,在键值AutoRunHKEY_CURRENT_USER\Software\Microsoft\Command Processor(仅限当前用户)或 HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor(所有用户):

    • 例如,您可以使用 PowerShell 为您创建这个值:
# Auto-execute `chcp 65001` whenever the current user opens a `cmd.exe` console
# window (including when running a batch file):
Set-ItemProperty 'HKCU:\Software\Microsoft\Command Processor' AutoRun 'chcp 65001 >NUL'

可选阅读:为什么 Windows PowerShell ISE 是一个糟糕的选择:

虽然 ISE 确实比控制台有更好的 Unicode 渲染 支持,但它通常是一个糟糕的选择:

  • 首先,ISE 过时:它不支持 PowerShell Core,所有未来开发的方向,它不是 cross-platform,不像两个 PowerShell 版本的新总理 IDE,Visual Studio Code,它已经说 UTF- PowerShell Core 默认情况下为 8,并且可以配置为 Windows PowerShell。

  • ISE 通常是开发 脚本的环境,而不是运行安装它们 的环境生产(如果您(也)为其他人编写脚本,您应该假设它们将在 控制台 中 运行);值得注意的是,关于 运行ning 代码,ISE 的行为与常规控制台的行为不同:

    • 对运行ning 外部程序的支持不佳,不仅仅是因为缺乏支持interactive那些(见下一点),还有关于字符编码:ISE错误地假设外部程序默认使用ANSI代码页,而实际上它是 OEM 代码页。例如,默认情况下,这个简单的命令试图简单地传递从 cmd.exe 回显的字符串,但会出现故障(请参阅下面的修复):
      cmd /c echo hü | Write-Output

    • Dot-sourcing script-file 调用而不是 运行 在 子范围内调用它们(后者是在常规控制台 window 中发生的情况),即在 非常相同的范围内甚至 重复 调用 运行 。这可能会导致细微的错误,其中前一个 运行 留下的定义会影响后续的定义。

  • 正如 eryksun 指出的那样,ISE 不支持 运行ning interactive 外部控制台程序,即需要用户输入的:

The problem is that it hides the console and redirects the process output (but not input) to a pipe. Most console applications switch to full buffering when a file is a pipe. Also, interactive applications require reading from stdin, which isn't possible from a hidden console window. (It can be unhidden via ShowWindow, but a separate window for input is clunky.)

  • 如果您愿意接受该限制,将活动代码页切换到 65001 (UTF-8) 以便与外部程序进行正确通信需要一个笨拙的解决方法:

    • 您必须首先通过 运行ning any 外部程序强制创建隐藏控制台 window 来自 built-in 控制台,例如 chcp - 你会看到一个控制台 window 短暂闪烁。

    • 只有然后才能设置[console]::OutputEncoding(和$OutputEncoding)为UTF-8,如上图(如果隐藏控制台尚未创建,您将获得 handle is invalid error).


[1] 在 PowerShell 中,如果您从不调用 外部 程序,则无需担心系统区域设置(活动代码页):PowerShell-native 命令和 .NET 调用始终通过 UTF-16 字符串(本机 .NET 字符串)进行通信,并且在文件中 I/O 应用独立于系统区域设置的默认编码。同样,因为 Unicode 版本的 Windows API 函数用于打印到控制台和从控制台读取,所以 non-ASCII 字符总是正确打印(在控制台的渲染限制内)。
cmd.exe 中,相比之下,系统区域设置对文件 I/O 很重要(使用 <> 重定向,但值得注意的是包括 batch-file 源采用的编码代码),不仅用于与外部程序通信 in-memory(例如在 for /f 循环中读取程序输出时)。

[2] 在 PowerShell v4- 中,静态 ::new() 方法不可用,请使用 $OutputEncoding = (New-Object System.Text.UTF8Encoding).psobject.BaseObject。请参阅 GitHub issue #5763 了解为什么需要 .psobject.BaseObject 部分。

Powershell ISE 完美显示韩语。这是一个用 utf8 编码的示例文本文件,它可以工作:

PS C:\Users\js> cat .\korean.txt

The Korean language (South Korean: 한국어/韓國語 Hangugeo; North 
Korean: 조선말/朝鮮말 Chosŏnmal) is an East Asian language
spoken by about 77 million people.[3]

由于 ISE 随 Windows10 的每个版本一起提供,因此我不认为它已过时。我不同意谁删除了我的原始答案。

ISE 有一些限制,但可以使用外部命令完成一些脚本:

echo 'list volume' | diskpart # as admin
cmd /c echo hi

编辑:

如果你有 Windows 10 1903,你可以从 Microsoft Store https://devblogs.microsoft.com/commandline/introducing-windows-terminal/ 下载 Windows 终端,韩语文本可以在那里工作。 Powershell 5 需要文本格式为带 bom 的 UTF8 或 UTF16。

编辑 2:

看起来理想的是 windows 终端 + powershell 7 或 vscode + powershell 7,用于粘贴字符和输出。

编辑 3:

即使在 EDIT2 的情况下,一些 unicode 字符也无法粘贴,例如 (U+21C6),或 unicode spaces。只有 Osx 中的 PS7 有效。