在Powershell中显示Unicode

问题描述 投票:19回答:3

虽然Powershell几乎不可能实现,但我想要实现的目标却相当简单。

我想显示文件的完整路径,其中一些文件的名称中包含阿拉伯语,中文,日语和俄语字符

我总是得到一些难以理解的输出,例如下面显示的enter image description here

在控制台中看到的输出正在被另一个脚本消耗。输出包含?而不是实际的人物。

执行的命令是

(Get-ChildItem -Recurse -Path "D:\test" -Include *unicode* | Get-ChildItem -Recurse).FullName

是否有任何简单的方法来启动PowerShell(通过命令行或以任何方式写入脚本),以便正确地看到输出。

附:我在Stack Overflow上经历了许多类似的问题,但除了称之为Windows控制台子系统问题之外,没有其他任何输入。

powershell unicode utf-8 terminal windows-console
3个回答
36
投票

请注意,类似Unix的平台上的PowerShell Core终端窗口默认情况下是UTF-8感知的(通常,现在,鉴于现代类Unix平台使用基于UTF-8的语言环境)。 在Windows上,从PowerShell Core 6.2.0开始还不是这样,但应尽快实现 - 请参阅this GitHub issue

使您的Windows PowerShell控制台窗口符合Unicode(UTF-8):

  • 选择一个TrueType(TT)字体,该字体支持要在控制台中正确显示其特征的特定脚本(编写系统,字母): 重要提示:虽然所有TrueType字体原则上都支持Unicode,但它们通常只支持所有Unicode字符的子集,即与特定脚本(书写系统)相对应的字符,例如拉丁文脚本,西里尔文(俄文)脚本,...... 在您的特定情况下 - 如果您必须支持阿拉伯语以及中文,日语和俄语字符 - 您唯一的选择是SimSun-ExtB,仅适用于Windows 10。 有关Windows字体针对哪些脚本(字母)的列表,请参阅Wikipedia。 要更改字体,请单击窗口左上角的图标并选择Properties,然后切换到Fonts选项卡并选择感兴趣的TrueType字体。 有关如何提供其他字体的信息,请参阅this SU answernot2quibit
  • 另外: 控制台窗口的代码页必须切换到65001,即UTF-8代码页(通常使用chcp 65001完成,但下面的PowerShell命令会隐式执行)。 必须指示PowerShell使用UTF-8与外部实用程序通信,无论是在向外部程序发送输入还是从外部程序接收输出时。

Windows PowerShell中的以下魔术咒语就是这样做的(如上所述,这隐式执行chcp 65001):

$OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding =
                    New-Object System.Text.UTF8Encoding

要保留这些设置,即默认情况下将您的未来交互式PowerShell会话设置为UTF-8,请将上面的命令添加到$PROFILE文件中。

重要:

  • 这些设置假定您与之通信的任何外部实用程序都需要UTF-8编码的输入并生成UTF-8输出。 例如,用Node.js编写的CLI符合该标准。 Python脚本 - 如果用UTF-8支持编写 - 也可以处理UTF-8。
  • 相比之下,这些设置可能会破坏(较旧的)实用程序,这些实用程序只需要系统的传统OEM代码页所暗示的单字节编码。 在Windows 8.1中,这甚至包括标准的Windows实用程序,如find.exefindstr.exe,已在Windows 10中修复。 请参阅本文的底部,了解如何根据需要临时切换到UTF-8来绕过此问题,以便调用给定的实用程序。

Optional background information

eryksun的所有投入的帽子的提示。

  • 当TrueType字体处于活动状态时,控制台窗口缓冲区正确保留(非ASCII)Unicode字符。即使它们没有正确呈现;也就是说,尽管它们可能通常表现为?,表示当前字体缺乏支持,但您可以在不丢失信息的情况下将这些字符复制并粘贴到其他位置,正如eryksun所观察到的那样。
  • 即使没有首先切换到代码页65001,PowerShell也能够将Unicode字符输出到控制台。 但是,这本身并不能保证其他程序能够正确处理这样的输出 - 见下文。
  • 当通过stdout(管道)与外部程序通信时,它使用$OutputEncoding首选项变量中指定的字符编码,在Windows PowerShell中默认为ASCII(!),这意味着任何非ASCII字符都被音译为文字?字符,导致信息丢失。 (相比之下,值得称道的是,PowerShell Core现在使用(无BOM)UTF-8作为默认编码,无处不在。) 相比之下,将非ASCII参数(而不是stdout(管道)输出)传递给外部程序似乎不需要特殊配置(我不清楚为什么这样做);例如,即使使用默认配置,以下Node.js命令也会正确返回€: 1node -pe "process.argv[1] + ': ' + process.argv[1].length" €
  • [Console]::OutputEncoding: 控制在控制台将程序输出转换为控制台显示字符时控制的字符编码。 还告诉PowerShell从外部程序捕获输出时要采用的编码方式。 结果是,如果你需要从产生UTF-8的程序中捕获输出,你需要将[Console]::OutputEncoding设置为UTF-8;设置$OutputEncoding只涵盖输入(到外部程序)方面。
  • [Console]::InputEncoding将键盘输入的编码设置到控制台中。
  • 如果在整个会话期间将控制台切换为UTF-8不是一个选项,则可以暂时为给定的呼叫执行此操作: # Save the current settings and temporarily switch to UTF-8. $oldOutputEncoding = $OutputEncoding; $oldConsoleEncoding = [Console]::OutputEncoding $OutputEncoding = [Console]::OutputEncoding = New-Object System.Text.Utf8Encoding # Call the UTF-8 program, using Node.js as an example. # This should echo '€' (`U+20AC`) as-is and report the length as *1*. $captured = '€' | node -pe "require('fs').readFileSync(0).toString().trim()" $captured; $captured.Length # Restore the previous settings. $OutputEncoding = $oldOutputEncoding; [Console]::OutputEncoding = $oldConsoleEncoding
  • 旧版Windows(早期版本W10)存在问题: chcp的有效65001值打破了某些外部程序的控制台输出甚至是旧版Windows中的批处理文件,最终可能源于WriteFile() Windows API函数中的错误(也被标准C库使用),如65001中所讨论的那样,错误地报告了代码页this blog post生效的字符数而不是字节数。 根据bobince对2008年this answer的评论,由此产生的症状是:“我的理解是返回字节数的调用(例如fread / fwrite / etc)实际上返回了一些字符数。导致各种各样的症状,例如输入读数不完整,fflush挂起,批处理文件损坏等。“
  • eryksun建议ConEmu作为原生Windows控制台窗口的优秀替代品。 根据他的说法,这将解决“旧的GDI实现无法处理复杂脚本,非BMP字符或自动回退字体”。

4
投票

阐述了Alexander Martin's answer。出于测试目的,我使用来自不同Unicode子范围的valid names创建了一些文件夹和文件,如下所示:

valid names

例如,使用Courier New控制台字体,在PowerShell控制台中显示替换符号而不是CJK字符:

Courier New

另一方面,使用SimSun控制台字体,(显示不太清楚)替换符号显示而不是阿拉伯语和希伯来语字符,而CJK字符似乎显示正确:

SimSun

请注意,仅显示所有替换符号,而保留真实字符,如下面的PowerShell控制台上的“复制和粘贴”中所示:

PS D:\PShell> (Get-ChildItem 'D:\bat\UnASCII Names\' -Dir).Name
Arabic (عَرَبِيّ‎)
CJK (中文(繁體))
Czech (Čeština)
Greek (Γρεεκ)
Hebrew (עִבְרִית)
Japanese (日本語)
MathBoldScript (𝓜𝓪𝓽𝓱𝓑𝓸𝓵𝓭𝓢𝓬𝓻𝓲𝓹𝓽)
Russian (русский язык)
Türkçe (Türkiye)
‹angles›
☺☻♥♦

为了完整起见,这里是适用于Enable More Fonts for the Windows Command Prompt的注册表值(这适用于Windows PowerShell控制台):

(Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console\TrueTypeFont' |
    Select-Object -Property [0-9]* | Out-String).Split( 
        [System.Environment]::NewLine, 
        [System.StringSplitOptions]::RemoveEmptyEntries) | 
     Sort-Object

样本输出:

0       : Consolas
00      : Source Code Pro
000     : DejaVu Sans Mono
0000    : Courier New
00000   : Simplified Arabic Fixed
000000  : Unifont
0000000 : Lucida Console
932     : *MS ゴシック
936     : *新宋体

0
投票

确保您的字体包含已安装的所有有问题的字符并设置为Win32控制台字体。如果我没记错,请单击窗口左上角的PowerShell图标,然后选择“属性”。生成的弹出对话框应该有一个选项来设置使用的字体。它可能必须是位图(.FON.FNT)字体。

© www.soinside.com 2019 - 2024. All rights reserved.