无BOM的写输出

如果我运行这样的命令:

Write-Output March > a.txt

我得到这个结果:

        U+FEFF    
M       U+004D          
a       U+0061          
r       U+0072    
c       U+0063          
h       U+0068 
        U+000D       
n      U+000A       

我不想要 BOM。我尝试了不同的操作,如下所示:

$OutputEncoding = [System.Text.UTF8Encoding]::new($false)
$PSDefaultParameterValues['*:Encoding'] = 'utf8'
[Console]::InputEncoding = [System.Text.UTF8Encoding]::new($false)
[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)

但他们似乎都没有解决这个问题。注意我使用的是 PowerShell 5.1。我确实看到了一些类似的问题,但与此不完全相同,因为他们正在处理管道和外部命令。

回答

tl;博士

  • 如果您希望 Windows PowerShell 的>运算符和 cmdletOut-File输出无BOM 的UTF-8,您唯一的选择是更改为该编码系统范围

    • 作为一次性步骤,运行intl.cpl以打开控制面板的区域设置,切换到Administrative选项卡,单击Change system locale...按钮并选中Beta: Use Unicode UTF-8 for worldwide language support

    • 在每个会话中运行以下命令,最好通过您的$PROFILE文件完成:

      • $PSDefaultParameterValues['*:Encoding'] = 'Default'
    • 有关此更改的重要影响和背景信息,请参阅下一节。

  • 否则,您必须直接使用 .NET API - 请参阅此问题的答案- 或围绕它们编写一个 PowerShell 友好的包装器 - 请参阅此答案。

  • 或者,您可以安装跨平台PowerShell [Core] v6+版本,该版本始终默认为无 BOM 的 UTF-8。


在 Windows 10 上,您可以将 Windows PowerShell默认设置为无 BOM 的 UTF-8 - 假设您愿意在系统范围内更改为这种编码:

  • 将您的系统区域设置(非 Unicode 程序的语言)更改为无 BOM 的 UTF-8,如本答案所述:

    • 简而言之:运行intl.cpl打开控制面板的区域设置,切换到Administrative选项卡,点击Change system locale...按钮并勾选Beta: Use Unicode UTF-8 for worldwide language support;请注意,您需要具有管理权限才能进行此更改,并且需要重新启动才能使更改生效。

    • 注意事项

      • 此更改将 OEM 和 ANSI 代码页设置为65001,即无 BOM 的 UTF-8,这会影响所有控制台窗口。

      • 从 Windows 10 版本 20H2 开始,此功能仍处于测试阶段,可能会破坏传统的控制台应用程序。

  • 然后,在 Windows PowerShell v5.1 中,将以下内容添加到您的$PROFILE文件中(这在 PowerShell [Core] v6+ 中不是必需的):

    • $PSDefaultParameterValues['*:Encoding'] = 'Default'
    • $OutputEncoding = [System.Text.Utf8Encoding]::new($false)

有了这个效果:

  • 所有文件写入[1]具有一个视窗PowerShell命令-Encoding参数然后将默认为BOM-少UTF-8(Default表示活性ANSI代码页,那么这将是65001,即BOM-少UTF-8) -特别是包括>/ Out-File/ Set-Content.

  • 然后,Windows PowerShell 还会将无BOM 文件读取为 UTF-8,包括源代码和通过Get-Content; 通常,Windows PowerShell 根据系统区域设置适当的 ANSI代码页解释无 BOM 文件(而 PowerShell [Core] v6+ 假定为 UTF-8)。

  • 由于 OEM 代码页是无 BOM 的 UTF-8(反映在chcp.com报告中65001),PowerShell 也将使用无 BOM 的 UTF-8:

    • 解释通过其 CLI 从外部接收的数据时。
    • 解释从 PowerShell 会话内的外部程序接收的数据时。
    • $OutputEncoding上面的分配还确保 PowerShell数据作为无 BOM 的 UTF-8发送到外部程序。(幸运的是,这个首选项变量现在在 PowerShell [Core] v6+ 中默认为无 BOM 的 UTF-8。)

请注意,上述内容还使所有PowerShell [Core] v6+控制台窗口在所有方面都使用无 BOM 的 UTF-8,只是您不需要$PROFILE添加(尽管它们没有危害)。


背景资料

  • > a.txt实际上与 相同| Out-File a.txt

  • Windows PowerShell中的>/ >>/默认为UTF-16LEOut-File ( “统一”)[2] ,它总是使用一个BOM。

  • 您有两种选择不同的编码方式

    • Out-File 显式使用并使用其-Encoding参数。

    • 在V5.1(也在PowerShell的[核心] V6 +),则可以设置为默认的编码>/ >>/Out-File经由$PSDefaultParameterValues偏好变量,如在讨论这个答案。

    • 然而,在Windows PowerShell中,在utf8对值-Encoding总是一个UTF-8编码与BOM,这样-除非你愿意切换到UTF-8的全系统,如上面解释的-创造的唯一途径BOM少UTF- 8个文件是直接使用.NET APIs

      • 请注意,在PowerShell [Core] v6+ 中,参数现在(更明智地)utf8接受的值-Encoding是指无BOM 的UTF-8 编码;如果您确实想要一个 UTF-8 BOM,请utf8BOM改用。

至于你尝试什么

您尝试的属性和变量仅与 PowerShell(在两个版本中)与外部程序通信的方式有关

  • $OutputEncoding确定 PowerShell 在通过管道向外部程序(后者可以通过 stdin(标准输入)读取数据)发送数据时使用的编码。

  • [Console]::OutputEncoding确定 PowerShell 在解释从外部程序接收到的输出时使用的编码。

  • [Console]::InputEncoding是编码时PowerShell使用接收数据从外部,当它的CLI被调用。

    • 警告:在这种情况下,您不能PowerShell 会话中更改此编码,因为那为时已晚。
    • 它必须由设置来电显示调用的PowerShell命令行,从cmd.exe最容易做用chcp 65001(见警告再次呼吁chcp内部PowerShell的下面)。虽然这不可避免地将两者 [Console]::InputEncoding[Console]::OutputEncoding,也就是通常需要。

笔记:

  • 在Windows中,[Console]::OutputEncoding[Console]::InputEncoding在默认情况下反映的遗留系统区域设置的OEM代码页的编码,通过报告chcp.com; 在类 Unix 平台(PowerShell [Core] v6+)上,它是(现在几乎无一例外)(无 BOM)UTF-8

  • 由于缓存这些 .NET 属性中的编码,您不能chcp.com从PowerShell内部使用来更改这些属性 - 而是直接分配所需的编码。

  • 有关更多信息,请参阅此答案,其中讨论了如何使 Windows 上的控制台窗口对外部程序始终使用无 BOM 的 UTF-8 。


[1] 从技术上讲,此首选项也适用于文件读取cmdlet,这对于无 BOM 的文件既不是绝对必要的,也不会对带有BOM 的文件造成任何损害- 即使该 BOM 指示 UTF-16 或 UTF- 32 编码 - 因为 BOM 总是覆盖-Encoding参数。

[2] 不幸的是,在 Windows PowerShell 中,不同 cmdlet 的默认编码差异很大 - 请参阅此答案的底部部分。


以上是无BOM的写输出的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>