将PowerShell的默认输出编码更改为UTF-8

181

默认情况下,当你在PowerShell中将命令的输出重定向到文件或者管道输出时,编码格式是UTF-16,这并不实用。我想将它更改为UTF-8。

可以通过将>foo.txt语法替换为| out-file foo.txt -encoding utf8来逐个更改,但每次都这样做很麻烦。

在PowerShell中持久设置方式是将其放入\Users\me\Documents\WindowsPowerShell\profile.ps1文件中;我验证过该文件确实会在启动时执行。

有人说可以使用$PSDefaultParameterValues = @{'Out-File:Encoding' = 'utf8'}来设置输出编码,但我尝试了一下,没有效果。

https://blogs.msdn.microsoft.com/powershell/2006/12/11/outputencoding-to-the-rescue/中讨论了$OutputEncoding似乎与此相关,但它讨论的是使用ASCII编码输出,这并不是实际发生的情况。

如何将PowerShell设置为使用UTF-8?


1
看起来Windows 11 默认使用 UTF-8 [Console]::OutputEncoding。 - undefined
3个回答

250
注意:
  • 下一个部分主要适用于Windows PowerShell

  • 在这两种情况下,这些信息适用于使PowerShell使用UTF-8来读写文件

    • 相比之下,有关如何将UTF-8编码的字符串发送和接收到和从外部程序中的信息,请参阅this answer
  • 现在可以进行全系统范围的UTF-8切换(自Windows 10的最新版本以来):请参阅this answer,但请注意以下注意事项

    • 该功能具有深远的影响,因为OEM和ANSI代码页都将设置为65001,即UTF-8;此外,该功能在撰写本文时(Windows 11 22H2)仍被视为测试版功能。
    • Windows PowerShell中,这仅对默认为ANSI代码页的那些cmdlet生效,特别是Set-Content,但不适用于Out-File / >,并且还适用于读取文件,特别是包括Get-Content和PowerShell本身读取源代码

Windows PowerShell 视角:

在PSv5.1或更高版本中,其中">"和">>"实际上是"Out-File"的别名,您可以通过"$PSDefaultParameterValues"首选项变量来设置">" / ">>" / "Out-File"的默认编码: $PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'
注意: 在Windows PowerShell(最新和最终版本为v5.1的传统版本)中,这总是创建带有伪BOM的UTF-8文件。 许多基于Unix的实用程序不识别此BOM(请参阅底部);请参阅此帖子以获取创建无BOM的UTF-8文件的解决方法。
在PowerShell(Core)v6+中,默认情况下是无BOM的UTF-8(请参阅下一节),但如果您确实希望在那里使用BOM,则可以使用'utf8BOM'
在PSv5.0或更低版本中,您无法更改">" / ">>"的编码,但是在PSv3或更高版本中,上述技术对于对"Out-File"的显式调用确实有效。 ("$PSDefaultParameterValues"首选项变量是在PSv3.0中引入的)。
在PSv3.0或更高版本中,如果您想为支持"-Encoding"参数的所有cmdlet(在PSv5.1+中包括">"和">>")设置默认编码,请使用: $PSDefaultParameterValues['*:Encoding'] = 'utf8'
如果您将此命令放在您的$PROFILE中,像Out-File和Set-Content这样的cmdlet将默认使用UTF-8编码。但请注意,这将成为一个会话全局设置,将影响所有未显式指定编码的命令/脚本,通过它们的-Encoding参数。
同样地,确保在您希望以相同方式运行的脚本或模块中包含这样的命令,以便它们在由其他用户或不同的机器运行时确实表现相同。然而,为了避免会话全局更改,使用以下形式创建$PSDefaultParameterValues的本地副本: $PSDefaultParameterValues = @{ '*:Encoding' = 'utf8' }
对于Windows PowerShell标准cmdlet中许多不一致的默认字符编码行为的摘要,请参阅底部部分。
自动变量$OutputEncoding与此无关,仅适用于PowerShell与外部程序的通信方式(PowerShell向其发送字符串时使用的编码方式),与输出重定向运算符和PowerShell cmdlet用于保存到文件的编码方式无关。
可选阅读:跨平台视角:PowerShell Core:
通过其PowerShell Core版本,PowerShell现在已经实现了跨平台,其编码默认为无BOM的UTF-8,与类Unix平台保持一致。
这意味着没有BOM的源代码文件被认为是UTF-8编码的,并且使用">" / "Out-File" / "Set-Content"默认为无BOM的UTF-8;显式使用"utf8" "-Encoding"参数也会创建无BOM的UTF-8,但您可以选择使用"utf8bom"值创建带有伪BOM的文件。
如果您在类Unix平台上使用编辑器创建PowerShell脚本,甚至在Windows上使用跨平台编辑器如Visual Studio Code和Sublime Text,生成的*.ps1文件通常不会有UTF-8伪BOM:
这在PowerShell Core上运行良好。
如果文件包含非ASCII字符,则在Windows PowerShell上可能会出现问题;如果您确实需要在脚本中使用非ASCII字符,请将它们保存为带有BOM的UTF-8。
没有BOM,Windows PowerShell会将您的脚本误解为使用传统的"ANSI"代码页进行编码(由系统区域设置确定,用于非Unicode应用程序;例如,在美国英语系统上为Windows-1252)。
相反,具有UTF-8伪BOM的文件在类Unix平台上可能会引起问题,因为它们会导致Unix实用程序(如cat、sed和awk)以及一些编辑器(如gedit)将伪BOM传递,即将其视为数据。
这可能不总是问题,但确实可能是问题,例如当您尝试在bash中将文件读入字符串时,比如text=$(cat file)或text=$(

Windows PowerShell中不一致的默认编码行为:

遗憾的是,Windows PowerShell中使用的默认字符编码非常不一致;如前一节所讨论的跨平台PowerShell Core版本已经令人称赞地解决了这个问题。

注意:

  • 以下内容并不打算涵盖所有标准cmdlet。

  • 现在,通过谷歌搜索cmdlet名称以查找其帮助主题,默认显示的是PowerShell Core版本的主题;在左侧主题列表上方使用版本下拉列表切换到Windows PowerShell版本。

  • 从历史上看,文档经常错误地声称ASCII是Windows PowerShell的默认编码;幸运的是,这个问题已经得到了纠正。


写入的Cmdlets:

Out-File> / >> 默认创建“Unicode” - UTF-16LE - 文件,其中每个ASCII范围的字符(也)由2个字节表示 - 这与Set-Content / Add-Content(见下一点)明显不同;New-ModuleManifestExport-CliXml 也创建UTF-16LE文件。

Set-Content(如果文件尚不存在/为空,则Add-Content)使用ANSI编码(由活动系统区域设置的ANSI遗留代码页指定的编码,PowerShell称之为Default)。

Export-Csv 确实创建ASCII文件,如文档所述,但请参阅下面关于-Append的注释。

Export-PSSession 默认创建带有BOM的UTF-8文件。

New-Item -Type File -Value 目前创建的是无BOM的UTF-8文件。

Send-MailMessage 帮助主题也声称ASCII编码是默认值 - 我个人尚未验证该声明。

Start-Transcript 无论如何都会创建带有BOM的UTF-8文件,但请参阅下面关于 -Append 的注释。

关于追加到现有文件的命令:

>> / Out-File -Append 不会尝试匹配文件的现有内容的编码。 也就是说,它们会盲目地应用默认编码,除非使用 -Encoding 进行其他指示,但 >> 不支持该选项(除非通过 $PSDefaultParameterValues 在PSv5.1+中间接设置,如上所示)。 简而言之:您必须知道现有文件内容的编码,并使用相同的编码进行追加。

Add-Content是一个值得称赞的例外:在没有明确的-Encoding参数的情况下,它会检测现有的编码并自动应用于新内容。谢谢,js2010。请注意,在Windows PowerShell中,如果现有内容没有BOM,则应用的是ANSI编码,而在PowerShell Core中则是UTF-8编码。

这种Out-File -Append / >>Add-Content之间的不一致性,也影响到PowerShell Core,在GitHub问题#9423中有讨论。

Export-Csv -Append 部分匹配现有的编码:如果现有文件的编码是ASCII/UTF-8/ANSI之一,它会盲目地追加UTF-8,但正确匹配UTF-16LE和UTF-16BE。
换句话说:在没有BOM的情况下,Export-Csv -Append 假设为UTF-8,而Add-Content 假设为ANSI。

Start-Transcript -Append 部分匹配现有的编码:它正确匹配带有BOM的编码,但在没有BOM的情况下默认使用可能有损失的ASCII编码。


Cmdlets that read (that is, the encoding used in the absence of a BOM):
Get-Content and Import-PowerShellDataFile default to ANSI (Default), which is consistent with Set-Content. ANSI is also what the PowerShell engine itself defaults to when it reads source code from files.
By contrast, Import-Csv, Import-CliXml and Select-String assume UTF-8 in the absence of a BOM, and so does the switch statement with its -File parameter.

1
有没有办法在Win10上强制不添加BOM? - mvorisek
1
默认情况下,PS 6 是 utf8nobom。除了 out-file 命令是“unicode”之外,大多数命令的 PS 5.1 是“ansi”。 - js2010
2
我并不反对,@EliaWeiss,但这是特指Windows PowerShell,而在PowerShell_Core中他们最终确实做到了。 - mklement0
2
@Marc:VS Code和其他现代跨平台编辑器默认使用UTF-8,但这意味着它们会误解ANSI编码的文件。记事本使用启发式算法猜测编码方式。 关键在于这只是一个猜测,因为任何UTF-8编码的文件也是一个技术上有效的ANSI编码文件(反之则不然)。 如果Windows上的所有内容都像类Unix平台一样,在没有BOM的情况下默认使用UTF-8,那将是很好的,但实际情况并非如此,尤其是在Windows PowerShell中,尽管幸运的是,在PowerShell Core中现在已经是这种情况了。 - mklement0
2
要查看当前值(如果有),只需键入“$PSDefaultParameterValues”。 - Sandburg
显示剩余20条评论

4

简单来说,使用:

write-output "your text" | out-file -append -encoding utf8 "filename"

您可能希望将脚本的某些部分放入大括号中,以便您可以重定向少数命令的输出:
{
  command 1
  command 2
} | out-file -append -encoding utf8 "filename"

1
引用问题中的话:“可以通过逐个替换“>foo.txt”语法为“| out-file foo.txt -encoding utf8”的方式来完成,但这样每次都要重复操作,很麻烦。”换句话说,您正在建议与OP试图避免的内容完全相同。 - mklement0
1
我认为应该删除 -append - Sasha Bond

1
使用PowerShell在Windows上进行输出重定向生成的转储文件采用UTF-16编码。为了解决这个问题,您可以尝试以下方法:
mysqldump.exe [options] --result-file=dump.sql

Reference link: mysqldump_result-file


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接