提问人:Paul Kim 提问时间:7/21/2019 最后编辑:Paul Kim 更新时间:11/16/2023 访问量:193402
在命令提示符/Windows Powershell (Windows 10) 中使用 UTF-8 编码 (CHCP 65001)
Using UTF-8 Encoding (CHCP 65001) in Command Prompt / Windows Powershell (Windows 10)
问:
一段时间以来,我一直在强制使用命令提示符和 Windows Powershell,但从 SO 和其他几个社区的问答帖子来看,这似乎是一个危险且低效的解决方案。Microsoft 是否提供了一个改进/完整的替代方案,可以在不手动更改注册表的情况下永久保存?如果没有,是否有公开宣布的时间表或议程将来在 Windows CLI 中支持 UTF-8?chcp 65001
chcp 65001
就我个人而言,我一直在使用韩语字符支持,但是在几个应用程序(如Neovim)中,反斜杠的奇怪显示和不正确/难以理解的显示,以及不支持的非韩语字符最近似乎成为一个更大的问题。chcp 949
\949
答:
可以将该命令放在 Powershell 配置文件中,该配置文件将在打开 Powershell 时自动运行它。但是,这不会对 cmd.exe 执行任何操作。chcp 65001
Microsoft目前正在开发一个改进的终端,该终端将具有完全的Unicode支持。它是开源的,如果你使用的是 Windows 10 版本 1903 或更高版本,则已经可以下载预览版。
或者,您可以使用第三方终端仿真器,例如 Terminus。
评论
chcp 65001
$OutputEncoding
chcp 65001
chcp
chcp 65001
cmd.exe
中工作,但在从 PowerShell 内部调用时则不然。PowerShell (Core) 至今仍默认为 OEM 代码页,例如 ;只有首选项变量设置为 UTF-8,它控制用于发送到外部程序的数据的编码。要获得完整的 UTF-8 支持,您需要使用接受的答案中涵盖的所有这些内容。chcp 65001
437
$OutputEncoding
$OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding
chcp 65001
cmd.exe
,则从 PowerShell 调用时也有效。但是,它不适用于 PowerShell 本身(及其内部命令,也称为 cmdlet),因为构建 PowerShell 的 .NET 会缓存编码,因此不会在更改的代码页上选取。可以防止此问题:它告诉 PowerShell 使用 UTF-8 代码页并更新控制台的代码页,也就是说,它的作用也类似于 .chcp 65001
cmd.exe
$OutputEncoding = ...
chcp 65001
注意:
这个答案展示了如何将Windows控制台(终端)中的字符编码切换到(无BOM)UTF-8系统范围(代码页),以便在与完全支持Unicode的外部(控制台)程序通信时,shell(如和PowerShell)正确地编码和解码字符(文本),也用于文件I/O[1]。
65001
cmd.exe
cmd.exe
相比之下,如果您关心的是控制台窗口中 Unicode 字符呈现的单独限制,请参阅此答案的中间部分和底部,其中还讨论了替代控制台(终端)应用程序。
Microsoft 是否提供了 chcp 65001 的改进/完整替代方案,无需手动更改注册表即可永久保存?
从(至少)Windows 10 版本 1903 开始,您可以选择将系统区域设置(非 Unicode 程序的语言)设置为 UTF-8,但截至撰写本文时,该功能仍处于测试阶段,从根本上具有深远的影响。
要激活它,请执行以下操作:
- 运行(在“控制面板”中打开区域设置)
intl.cpl
- 按照下面屏幕截图中的说明进行操作。
这会将系统的活动 OEM 和 ANSI 代码页都设置为
65001
,即 UTF-8 代码页,因此 (a) 使所有使用 OEM 代码页的未来控制台窗口默认为 UTF-8(就像在窗口中执行一样)和 (b) 还使使用 ANSI 代码页的旧版非 Unicode GUI 子系统应用程序, 使用 UTF-8。chcp 65001
cmd.exe
注意事项:
如果使用的是 Windows PowerShell,这还将使 Get-Content 和
Set-Content
以及 Windows PowerShell 默认的其他上下文,因此系统的活动 ANSI 代码页(特别是从无 BOM 文件读取源代码)默认为 UTF-8(PowerShell 核心(v6+) 总是如此)。这意味着,在没有参数的情况下,ANSI 编码的无 BOM 文件(这在历史上很常见)将被误读,并且创建的文件将是 UTF-8 而不是 ANSI 编码。
-Encoding
Set-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.AllUsersCurrentHost
chcp 65001
$OutputEncoding
- 请注意,从 PowerShell 会话内部运行是无效的,因为 .NET 在启动时缓存控制台的输出编码,并且不知道以后使用 ;此外,如前所述,需要设置 Windows PowerShell - 有关详细信息,请参阅此答案。
chcp 65001
chcp
$OutputEncoding
- 请注意,从 PowerShell 会话内部运行是无效的,因为 .NET 在启动时缓存控制台的输出编码,并且不知道以后使用 ;此外,如前所述,需要设置 Windows PowerShell - 有关详细信息,请参阅此答案。
$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(仅限当前用户)或(所有用户):AutoRun
HKEY_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)7+,所有未来的开发都将在这里进行,而且它不是跨平台的,这与两个PowerShell版本的新首要IDE不同,Visual Studio Code已经默认使用UTF-8用于PowerShell Core,并且可以配置为为Windows PowerShell这样做。
ISE通常是用于开发脚本的环境,而不是用于在生产环境中运行脚本(如果您正在为其他人编写脚本,则应假定它们将在控制台/Windows终端中运行);值得注意的是,在运行代码方面,ISE的行为与常规控制台/Windows终端的行为不同:
对运行外部程序的支持很差,不仅是因为缺乏支持的交互式程序(见下一点),而且在以下方面:
ISE点源脚本文件调用,而不是在子作用域中运行它们(后者是在常规控制台窗口/Windows终端中发生的情况);也就是说,在ISE中,重复调用在同一范围内运行。这可能会导致细微的错误,其中上次运行留下的定义可能会影响后续运行。
正如eryksun所指出的,ISE不支持运行交互式外部控制台程序,即那些需要用户输入的程序:
问题在于它隐藏了控制台并将进程输出(但不是输入)重定向到管道。当文件是管道时,大多数控制台应用程序都会切换到完全缓冲。此外,交互式应用程序需要从 stdin 读取数据,这无法从隐藏的控制台窗口中读取。(它可以通过 取消隐藏,但单独的输入窗口很笨拙。
ShowWindow
如果您愿意忍受该限制,则将活动代码页切换到 (UTF-8) 以便与外部程序进行正确通信需要一个尴尬的解决方法:
65001
您必须首先通过从内置控制台运行任何外部程序来强制创建隐藏的控制台窗口,例如,您将看到一个控制台窗口短暂闪烁。
chcp
只有这样,您才能将 (和 ) 设置为 UTF-8,如上所示(如果尚未创建隐藏的控制台,您将获得 )。
[console]::OutputEncoding
$OutputEncoding
handle 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
部分。
评论
ReadFile
chcp.com 65001
for /f
for /f
[console]::OutputEncoding
$OutputEncoding
>
Out-File
Set-Content
UTF-8
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 才能工作。⇆
评论
ShowWindow
OutputEncoding
[console]::OutputEncoding
AllocConsole
[console]::OutputEncoding
每当启动命令提示符时,键入一些命令(或其他命令)可以通过编辑注册表来完成。这是正确的方法,如以下所述:chcp
CMD /?
如果未在命令行上指定 /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"
评论
Active code page: 65001
>$null
chcp
[Console]::OutputEncoding
>$null
| Out-Null
$PROFILE
$OutputEncoding
评论
WriteFile
ReadFile
WriteConsoleW
ReadConsoleW