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

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

提问人:Paul Kim 提问时间:7/21/2019 最后编辑:Paul Kim 更新时间:11/16/2023 访问量:193402

问:

一段时间以来,我一直在强制使用命令提示符和 Windows Powershell,但从 SO 和其他几个社区的问答帖子来看,这似乎是一个危险且低效的解决方案。Microsoft 是否提供了一个改进/完整的替代方案,可以在不手动更改注册表的情况下永久保存?如果没有,是否有公开宣布的时间表或议程将来在 Windows CLI 中支持 UTF-8?chcp 65001chcp 65001

就我个人而言,我一直在使用韩语字符支持,但是在几个应用程序(如Neovim)中,反斜杠的奇怪显示和不正确/难以理解的显示,以及不支持的韩语字符最近似乎成为一个更大的问题。chcp 949\949

Windows PowerShell UTF-8 控制台应用程序

评论

0赞 Tomalak 7/21/2019
有趣,谢谢!(不过,投票最高的警告性评论已有 8 年的历史,我怀疑它们是否仍然适用。
1赞 Eryk Sun 7/21/2019
@Tomalak,在 Windows 8 之前,控制台将返回写入的解码 UTF-16 代码点数,这可能会导致缓冲编写器出现问题,这些编写器期望这是写入的 UTF-8 字节数,因为它应该如此。对于控制台,即使在 Windows 10 中,如果输入代码页设置为 UTF-8,由于控制台主机 conhost.exe 中的错误假设,你也将被限制为 7 位 ASCII。在 Windows 10 中,它会在缓冲区中以 null (“\0”) 的形式返回非 ASCII 字符。在旧版本中,读取成功,读取字节数为 0,类似于 EOF。WriteFileReadFile
2赞 Eryk Sun 7/21/2019
现代 Windows 程序应使用 Unicode 控制台函数,并且 .那么唯一的限制是控制台对Unicode的固有限制,即仅限于基本的多语言平面;不支持复杂的脚本和组合代码;如果所选字体没有字符的字形,则不支持字体回退。最终,Microsoft可能会更新经典控制台主机,通过切换到基于DirectWrite的实现来消除这些限制,但目前他们(和开源贡献者)的工作集中在新的Windows终端上。WriteConsoleWReadConsoleW
0赞 Henke 1/31/2023
相关。• 什么编码让 Å Ä Ö 工作 • 在命令提示符下使用 UTF-8 编码 (CHCP 65001) • 如何在 Windows 命令行中使用 Unicode 字符 • CHCP 65001 和 .bat 文件使瑞典语字符在 Windows 命令提示符中正确显示

答:

6赞 jfhr 7/21/2019 #1

可以将该命令放在 Powershell 配置文件中,该配置文件将在打开 Powershell 时自动运行它。但是,这不会对 cmd.exe 执行任何操作。chcp 65001

Microsoft目前正在开发一个改进的终端,该终端将具有完全的Unicode支持。它是开源的,如果你使用的是 Windows 10 版本 1903 或更高版本,则已经可以下载预览版

或者,您可以使用第三方终端仿真器,例如 Terminus

评论

1赞 mklement0 7/21/2019
遗憾的是,从 PowerShell 会话内部运行是无效的,因为 .NET 会在启动时缓存控制台的输出编码;此外,还需要设置 Windows PowerShell(但不是 PowerShell Core)。chcp 65001$OutputEncoding
1赞 WD40 10/24/2021
截至今天(我不知道它是什么时候更改的),可以在 cmd.exe 中工作。我在 Windows 10 家庭版 20H2 上安装了 Windows Terminal 1.10.2714.0,体验与 Windows PowerShell (5.1) 和 cmd.exe 相同(出于我的目的,我只是为了输出 UTF-8 字符)。有趣的是,PowerShell Core 7.1.5 已完全损坏。根据属性,全新安装声称使用代码页 65001,但其行为就像使用 437 一样。 报告 437,如果运行,它会报告 437,但这对编码没有实际影响。chcp 65001chcpchcp 65001
1赞 mklement0 1/26/2022
@WD40,始终cmd.exe工作,但在从 PowerShell 内部调用时则不然。PowerShell (Core) 至今仍默认为 OEM 代码页,例如 ;只有首选项变量设置为 UTF-8,它控制用于发送到外部程序的数据的编码。要获得完整的 UTF-8 支持,您需要使用接受的答案中涵盖的所有这些内容。chcp 65001437$OutputEncoding$OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding
0赞 WD40 5/1/2022
@mklement0感谢您的澄清。但从我对这个答案的阅读和理解来看,它使这个答案完全错误。 cmd.exe 做点什么,然后......可能会对 PowerShell 执行某些操作(如果放置在配置文件中)。我对 PowerShell 一无所知。chcp 65001
0赞 mklement0 5/1/2022
@WD40,是的,从 调用时始终有效,如果然后从 PowerShell 调用 cmd.exe,则从 PowerShell 调用时也有效。但是,它不适用于 PowerShell 本身(及其内部命令,也称为 cmdlet),因为构建 PowerShell 的 .NET 会缓存编码,因此不会在更改的代码页上选取。可以防止此问题:它告诉 PowerShell 使用 UTF-8 代码页并更新控制台的代码页,也就是说,它的作用也类似于 .chcp 65001cmd.exe$OutputEncoding = ...chcp 65001
174赞 mklement0 7/21/2019 #2

注意:

  • 这个答案展示了如何将Windows控制台(终端)中的字符编码切换到(无BOM)UTF-8系统范围(代码页),以便在与完全支持Unicode外部(控制台)程序通信时,shell(如和PowerShell)正确地编码和解码字符(文本),也用于文件I/O[1]。 65001cmd.execmd.exe

  • 相比之下,如果您关心的是控制台窗口中 Unicode 字符呈现的单独限制,请参阅此答案的中间部分和底部,其中还讨论了替代控制台(终端)应用程序。


Microsoft 是否提供了 chcp 65001 的改进/完整替代方案,无需手动更改注册表即可永久保存?

从(至少)Windows 10 版本 1903 开始,您可以选择系统区域设置非 Unicode 程序的语言)设置为 UTF-8,但截至撰写本文时,该功能仍处于测试阶段,从根本上具有深远的影响

要激活它,请执行以下操作:

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

Control Panel > Region > Administrative

  • 这会系统的活动 OEM 和 ANSI 代码页都设置为 65001,即 UTF-8 代码页,因此 (a) 使所有使用 OEM 代码页的未来控制台窗口默认为 UTF-8(就像在窗口中执行一样)和 (b) 还使使用 ANSI 代码页的旧版非 Unicode GUI 子系统应用程序, 使用 UTF-8。chcp 65001cmd.exe

    • 注意事项

      • 如果使用的是 Windows PowerShell,这还将使 Get-Content 和 Set-Content 以及 Windows PowerShell 默认的其他上下文,因此系统的活动 ANSI 代码页(特别是从无 BOM 文件读取源代码默认为 UTF-8(PowerShell 核心(v6+) 总是如此)。这意味着,在没有参数的情况下,ANSI 编码的无 BOM 文件(这在历史上很常见)将被误读,并且创建的文件将是 UTF-8 而不是 ANSI 编码。-EncodingSet-Content

        • 同样,旧版(非 Unicode)非控制台应用程序误解 ANSI 编码的文件
      • 选择一种 TT (TrueType) 字体,但即使它们通常也只支持所有字符的子集,因此您可能需要尝试使用特定字体来查看是否表示您关心的所有字符 - 有关详细信息,请参阅此答案,其中还讨论了具有更好 Unicode 呈现支持的替代控制台(终端)应用程序。

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

  • 但是,对于 Windows PowerShell,这还不够

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

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

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

  • 对于 PowerShell(两个版本),请将以下行添加到(仅限当前用户)或(所有用户)文件(相当于 ,并辅以设置首选项变量以指示 PowerShell 通过 UTF-8 的管道将数据发送到外部程序:$PROFILE$PROFILE.AllUsersCurrentHostchcp 65001$OutputEncoding

    • 请注意,从 PowerShell 会话内部运行是无效的,因为 .NET 在启动时缓存控制台的输出编码,并且不知道以后使用 ;此外,如前所述,需要设置 Windows PowerShell - 有关详细信息,请参阅此答案chcp 65001chcp$OutputEncoding
$OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding
  • 例如,下面是以编程方式添加此行的快速方法:$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,通过注册表定义一个自动运行命令,值为 key(仅限当前用户)或(所有用户):AutoRunHKEY_CURRENT_USER\Software\Microsoft\Command ProcessorHKEY_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)7+,所有未来的开发都将在这里进行,而且它不是跨平台的,这与两个PowerShell版本的新首要IDE不同,Visual Studio Code已经默认使用UTF-8用于PowerShell Core,并且可以配置为为Windows PowerShell这样做。

  • ISE通常是用于开发脚本的环境,而不是用于在生产环境中运行脚本(如果您正在为其他人编写脚本,则应假定它们将在控制台/Windows终端运行);值得注意的是,运行代码方面,ISE的行为与常规控制台/Windows终端的行为不同

    • 对运行外部程序的支持很差,不仅是因为缺乏支持的交互式程序(见下一点),而且在以下方面:

      • 字符编码

        • ISE 错误地假定外部程序默认使用 ANSI 代码页,而实际上它是 OEM 代码页。例如,默认情况下,这个简单的命令试图简单地传递一个从 through 回显的字符串,会出现故障(有关修复,请参见下文):cmd.exe
          cmd /c echo hü | Write-Output

        • 首选项变量默认为 UTF-8 而不是旧版 OEM 代码页(如在常规控制台中),并且不恰当地将 UTF-8 BOM 附加到通过管道传递给外部程序的(第一个)字符串 - 请参阅此答案$OutputEncoding

      • 不恰当地将 stderr 输出呈现为 PowerShell 错误:请参阅此答案

    • ISE点源脚本文件调用,而不是在子作用域中运行它们(后者是在常规控制台窗口/Windows终端中发生的情况);也就是说,在ISE中,重复调用在同一范围内运行。这可能会导致细微的错误,其中上次运行留下的定义可能会影响后续运行。

  • 正如eryksun所指出的,ISE不支持运行交互式外部控制台程序,即那些需要用户输入的程序:

问题在于它隐藏了控制台并将进程输出(但不是输入)重定向到管道。当文件是管道时,大多数控制台应用程序都会切换到完全缓冲。此外,交互式应用程序需要从 stdin 读取数据,这无法从隐藏的控制台窗口中读取。(它可以通过 取消隐藏,但单独的输入窗口很笨拙。ShowWindow

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

    • 您必须首先通过从内置控制台运行任何外部程序来强制创建隐藏的控制台窗口,例如,您将看到一个控制台窗口短暂闪烁。chcp

    • 只有这样,您才能将 (和 ) 设置为 UTF-8,如上所示(如果尚未创建隐藏的控制台,您将获得 )。[console]::OutputEncoding$OutputEncodinghandle is invalid error


[1] 在 PowerShell 中,如果从不调用外部程序,则无需担心系统区域设置(活动代码页):PowerShell 本机命令和 .NET 调用始终通过 UTF-16 字符串(本机 .NET 字符串)进行通信,并且在文件 I/O 上应用独立于系统区域设置的默认编码。同样,由于 Windows API 函数的 Unicode 版本用于打印到控制台和从控制台读取,因此非 ASCII 字符始终正确打印(在控制台的呈现限制范围内)。
相比之下,在 cmd.exe 中,系统语言环境对文件 I/O(具有 <> 重定向,但特别包括批处理文件源代码的编码),而不仅仅是与内存中的外部程序通信(例如在 for /f 循环中读取程序输出时)。

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

评论

4赞 Eryk Sun 7/21/2019
将控制台的输入代码页设置为 UTF-8 会限制读取 7 位 ASCII 输入的旧程序。(输出将在 Windows 8 之前中断,但 Windows 7 无论如何都接近 EOL。如果将系统区域设置设置为 UTF-8,我建议将“HKEY_CURRENT_USER\Console\%SystemRoot%_system32_cmd.exe”(以及其他感兴趣的窗口标题)的“CodePage”值设置为旧版 OEM 代码页,以便旧版非 Unicode 控制台应用程序将继续在你的区域设置中正常工作。不要使用 ,除非在批处理脚本中暂时使用,例如 for 循环。ReadFilechcp.com 65001for /f
3赞 Eryk Sun 7/21/2019
PowerShell 和 CMD 使用控制台的 Unicode API,因此控制台代码页的这些设置仅与 shell 在运行外部控制台应用程序时设置的输入和输出控制台代码页有关,而与 shell 内部的任何内容(如 cmdlet)无关,除非 shell 在处理文件和管道中的文本时使用输入和输出编码设置。我不确定如何在 PowerShell 中使用这些设置,但 CMD 在解码批处理脚本和从循环中的程序读取管道输出时使用控制台输出代码页。for /f
2赞 mklement0 7/22/2019
@eryksun:对于 PowerShell:外部程序的 stdout 输出根据 解码,通过管道发送到外部程序的文本根据 preference 变量进行编码。Re 文件:Windows PowerShell:读取默认为 ANSI,除非有 BOM;将默认值写入 UTF-16LE 和 / 和 ANSI 和 ;幸运的是,PowerShell Core_now在所有这些方案中始终使用无 BOM 的 UTF-8。[console]::OutputEncoding$OutputEncoding>Out-FileSet-Content
1赞 dyomas 9/16/2020
更改系统区域设置后,VS(我的版本是 16.7.2)有一个令人不快的惊喜:所有包含 UTF-8 的文件都会通过将 UTF-8 字符替换为某些 Unicode 占位符来强制损坏。每个打开的文件之前都会出现大红色错误消息
5赞 Frank N 4/26/2021
我做对了吗?现在是公元 2021 年。世界上最大的操作系统默认不处理文本文件?(但是 1 年代的拉丁语 – ISO-8859-1 或类似的 8 位编码?UTF-8
0赞 js2010 7/22/2019 #3

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 随 Windows 10 的每个版本一起提供,因此我不认为它已经过时。我不同意谁删除了我的原始答案。

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 需要文本格式为 UTF8 with bom 或 UTF16。

编辑2:

似乎理想的是 Windows 终端 + powershell 7 或 vscode + powershell 7,用于粘贴字符和输出。

编辑3:

即使在 EDIT2 情况下,也无法粘贴某些 unicode 字符,如 (U+21C6) 或 unicode 空格。只有 Osx 中的 PS7 才能工作。

评论

1赞 Paul Kim 7/22/2019
ISE当然是一个强大的工具,但有些操作不能仅靠ISE完成。例如,我将 Neovim 与 PowerShell 一起使用终端,这是 ISE 的可用选项。
2赞 Eryk Sun 7/22/2019
ISE 是用于运行 PowerShell 脚本的环境。它不支持交互式控制台应用程序(例如 diskpart.exe、python.exe shell)。问题在于它隐藏了控制台并将进程输出(但不是输入)重定向到管道。当文件是管道时,大多数控制台应用程序都会切换到完全缓冲。此外,交互式应用程序需要从 stdin 读取数据,这无法从隐藏的控制台窗口中读取。(它可以通过 取消隐藏,但单独的输入窗口很笨拙。ShowWindow
0赞 mklement0 7/23/2019
js2010:一位版主删除了你的答案,我猜为什么它可能被标记为低质量的答案,因为它没有提供任何解释。我将重新发布与您的答案一起删除的评论,但为了补充@eryksun的观点,以他们对我的答案的评论为基础:如果将活动限制为仅 PowerShell 本机命令,则无需担心代码页 - 无论是在控制台中还是在 ISE 中。当您与外部(控制台)应用程序通信时,代码页很重要,因此 ISE 是一个比控制台更糟糕的选择。
1赞 Eryk Sun 7/23/2019
@mklement0,PowerShell 将自己作为中间人插入到管道和文件的重定向中,因此它用于解码程序输出的编码非常重要。但这难道不是改变变量的问题吗?如果它是 的函数,我会觉得很奇怪。无论如何,尝试设置后者一开始会失败,因为powershell_ise.exe最初没有控制台。它调用以获取控制台,并在运行外部控制台应用程序之前隐藏窗口。之后我们可以设置 .OutputEncoding[console]::OutputEncodingAllocConsole[console]::OutputEncoding
1赞 Eryk Sun 7/23/2019
@mklement0、ConEmu 或新的 Windows 终端都是不错的选择。在 Windows 10 中,我很确定两者都在利用新的伪控制台功能,但 ConEmu 也可以在旧版本的 Windows 中使用。conhost.exe 和新式程序之间 Unicode 处理的区别在于 conhost.exe 基于经典的 Windows GDI API,而较新的程序使用 DirectWrite API。
2赞 Sangbok Lee 4/6/2023 #4

每当启动命令提示符时,键入一些命令(或其他命令)可以通过编辑注册表来完成。这是正确的方法,如以下所述:chcpCMD /?

如果未在命令行上指定 /D,则当 CMD.EXE 启动时, 它查找以下 REG_SZ/REG_EXPAND_SZ 注册表变量, 如果存在其中之一或两者,则首先执行它们。

HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\AutoRun

    and/or

HKEY_CURRENT_USER\Software\Microsoft\Command Processor\AutoRun

现在是 2023 年,好消息。使用 Windows 终端,不需要编辑注册表或创建其他批处理文件。在 Windows 终端中,转到“设置”>“配置文件”并找到“命令提示符”,然后将“命令行”从“(默认)更改为 .这很简单。%SystemRoot%\System32\cmd.exe%SystemRoot%\System32\cmd.exe /K "chcp 65001"

*已添加:如果您使用 PowerShell 而不是命令提示符,请将其添加到命令行设置:。在我的例子中,默认值是:-NoExit -Command "chcp 65001"

%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe

然后改为:

%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe -NoExit -Command "chcp 65001"

评论

0赞 mklement0 11/1/2023
谢谢,但这将在每个会话开始时打印,如果您尝试抑制它,例如使用 ,则调用将相对于 无效,因为它会与其原始代码页一起缓存。即使不使用 或 ,如果任何文件恰好包含任何被捕获、重定向或禁止的外部程序调用,则仍可能出现此问题。简而言之:不幸的是,这不是一个可靠的方法(在 Windows PowerShell 中,您也需要设置)。Active code page: 65001>$nullchcp[Console]::OutputEncoding>$null| Out-Null$PROFILE$OutputEncoding