无 BOM 的写入输出

Write-Output with no 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)

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

tl;dr

  • 如果你想要WindowsPowerShell的>运算符和cmdlets比如Out-File输出BOM-lessUTF -8,您唯一的选择是更改为该编码 system-wide:

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

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

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

  • 否则,您必须直接使用 .NET API - 请参阅 this question - or write a PowerShell-friendly wrapper around them - see this answer.

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


在 Windows 10 上,您可以使 Windows PowerShell 始终默认为无 BOM UTF-8 - 假设您'我愿意更改为此编码 system-wide:

  • 将您的系统区域设置(非 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.

      • 自 Windows 10 版本 20H2 起,此功能仍处于测试阶段,可能会破坏旧版控制台应用程序。

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

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

生效后:

  • 所有文件写入[1] Windows 具有 -Encoding 参数的 PowerShell cmdlet 将默认为无 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+ 控制台 windows 在所有方面都使用 BOM-less UTF-8,除了您不需要 $PROFILE 添加(尽管它们没有害处)。


背景资料:

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

    相同
  • Windows PowerShell 的 > / >> / Out-File 默认为 UTF-16LE ("Unicode")[2],它总是使用 BOM。

  • 您有两个选择不同编码的选项:

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

    • 在 v5.1(以及 PowerShell [Core] v6+)中,您可以通过以下方式设置 > / >> / Out-File 的默认编码$PSDefaultParameterValues 偏好变量,如 .

      中所讨论
    • 但是,在 Windows PowerShell 中,-Encodingutf8 值为 总是 UTF-8 编码带有 BOM,所以 - 除非你愿意切换到 UTF-8 system-wide,如上所述 - 创建 无 BOM UTF-8 文件的唯一方法是 直接使用 .NET API.

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

至于你试过的:

您尝试的属性和变量仅与 PowerShell - 在两个版本中 - 如何与外部程序通信有关:

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

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

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

    • 警告:在这种情况下,您无法在 的 PowerShell 会话中更改此编码,因为那样做就太晚了。
    • 它必须由调用者设置,调用PowerShell CLI之前,cmd.exe最容易完成使用 chcp 65001(请参阅下面的从 inside PowerShell 重新调用 chcp 的注意事项)。虽然这总是设置 [Console]::InputEncoding[Console]::OutputEncoding,但这通常是可取的。

注:

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

  • 由于 缓存 这些 .NET 属性中的编码,您不能使用 inside[=260] 中的 chcp.com =] PowerShell 更改这些属性 - 相反,直接分配所需的编码。

  • 有关详细信息,请参阅 ,其中讨论了如何使 Windows 上的控制台 windows 始终使用无 BOM 的 UTF-8 关于外部程序.


[1] 从技术上讲,此首选项也适用于 file-reading cmdlet,这对于无 BOM 文件来说既不是绝对必要的,也不是对文件 使用 BOM 的任何危害 - 即使 BOM 指示 UTF-16 或 UTF-32 编码 - 因为 BOM 总是覆盖 -Encoding 参数。

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

如果您只使用 ascii 字符,set-content 在 powershell 5.1 中就可以了:

Write-Output March | set-content a.txt
'March' | set-content a.txt

或者在您的 $profile 中使用此哈希表将输出文件的默认编码设置为 ascii。 out-file默认编码为utf16或'unicode'编码。 '>' 是输出文件的快捷方式。密钥的名称必须用引号引起来,因为它包含一个冒号。 utf8nobom 直到更高版本的 powershell 才可用。 '>>' 也调用输出文件并且可以在同一个文件中混合编码。

$PSDefaultParameterValues = @{ 'out-file:encoding' = 'ascii' }

然后这将生成一个 ascii 文件:

Write-Output March > a.txt