无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 [Core] v6+ 中,参数现在(更明智地)
-
至于你尝试了什么:
您尝试的属性和变量仅与 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 的默认编码差异很大 - 请参阅此答案的底部部分。