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

Posted

技术标签:

【中文标题】将 PowerShell 的默认输出编码更改为 UTF-8【英文标题】:Changing PowerShell's default output encoding to UTF-8 【发布时间】:2017-02-27 04:02:20 【问题描述】:

默认情况下,当您将命令的输出重定向到文件或将其通过管道传输到 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 PowerShell

跨平台PowerShell Core (v6+)版本请参阅部分之后

在这两种情况下,信息都适用于使 PowerShell 使用 UTF-8 来读取和写入 文件

相比之下,有关如何向外部程序发送和接收 UTF-8 编码的字符串的信息,请参阅@987654322 @。

PSv5.1或更高版本中,>>>实际上是Out-File的别名,您可以>/>>设置默认编码/Out-File 通过$PSDefaultParameterValues 偏好变量

$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8' 注意:

Windows PowerShell(最新和最终版本为 v5.1 的旧版本)中,这总是创建带有(pseudo) BOM.

许多基于 Unix 的实用程序无法识别此 BOM(见底部);有关创建无 BOM 的 UTF-8 文件的解决方法,请参阅 this post。

PowerShell (Core) v6+ 中,BOM-less UTF-8 是 默认值(见下部分),但如果您确实想要那里的 BOM,您可以使用'utf8BOM'

PSv5.0 或更低版本中,您无法更改 > / >> 的编码,但是,在 >PSv3 或更高版本,上述技术确实适用于显式调用 Out-File。 ($PSDefaultParameterValues 首选项变量是在 PSv3.0 中引入的)。

PSv3.0 或更高版本中,如果您想所有支持的 cmdlet 设置默认编码 -Encoding 参数(在 PSv5.1+ 中包括 >>>),使用:

$PSDefaultParameterValues['*:Encoding'] = 'utf8'

如果将此命令放在 $PROFILE 中,则 Out-FileSet-Content 等 cmdlet 将默认使用 UTF-8 编码,但请注意这使它成为一个会话全局设置,它将影响所有未通过-Encoding 参数明确指定编码的命令/脚本。

同样,确保在您的 脚本模块 中包含您希望以相同方式运行的命令,以便它们确实即使由另一个用户或不同的机器运行,行为也一样;但是,为避免会话-全局 更改,请使用以下表单创建$PSDefaultParameterValues本地 副本:

$PSDefaultParameterValues = @ '*:Encoding' = 'utf8'

有关许多 Windows PowerShell 标准 cmdlet 中非常不一致的默认字符编码行为的摘要,请参阅底部部分。


$OutputEncoding 自动变量无关,仅适用于 PowerShell 与外部程序的通信方式(PowerShell 在发送时使用的编码字符串)- 它与输出重定向运算符和 PowerShell cmdlet 用于保存到文件的编码无关。


选读:跨平台视角:PowerShellCore

PowerShell is now cross-platform,通过其 PowerShell Core 版本,其编码 - 明智地 - 默认为 BOM-less UTF-8,在符合类 Unix 平台。

这意味着没有 BOM 的源代码文件被假定为 UTF-8,使用 > / Out-File / Set-Content 默认为 BOM-less UTF-8;显式使用 utf8 -Encoding 参数也会创建 BOM-less UTF-8,但您可以选择使用 @987654361 创建带有 伪 BOM 的文件@值。

如果您在类 Unix 平台上使用编辑器创建 PowerShell 脚本,现在甚至在 Windows 上使用 Visual Studio Code 和 Sublime Text 等跨平台编辑器,生成的 *.ps1 文件将通常有 UTF-8 伪 BOM:

这在 PowerShell Core 上运行良好。 如果文件包含非 ASCII 字符,它可能会在 Windows PowerShell 上中断;如果您确实需要在脚本中使用非 ASCII 字符,请将它们保存为 UTF-8 与 BOM。 如果没有 BOM,Windows PowerShell(错误)会将您的脚本解释为在旧版“ANSI”代码页中编码(由 Unicode 之前的应用程序的系统区域设置确定;例如,美国英语系统上的 Windows-1252)。

相反,确实具有 UTF-8 伪 BOM 的文件在类 Unix 平台上可能会出现问题,因为它们会导致 Unix 实用程序,例如 catsed 和 @987654365 @ - 甚至一些编辑器如gedit - 通过传递伪BOM,即把它当作数据

这可能并不总是成为问题,但绝对可能是,例如当您尝试使用text=$(cat file)text=$(<file) 将文件读入bash 中的字符串时- 结果变量将包含伪 BOM 作为前 3 个字节。

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

很遗憾,Windows PowerShell 中使用的默认字符编码非常不一致;正如上一节所讨论的,跨平台的 PowerShell Core 版本已经很好地结束了这一点。

注意:

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

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

在撰写本文时,文档经常错误地声称 ASCII 是 Windows PowerShell 中的默认编码 - 请参阅 this GitHub docs issue。


编写的 Cmdlet:

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-less(!) UTF-8。

Send-MailMessage 帮助主题还声称 ASCII 编码是默认编码 - 我没有亲自验证该声明。

Start-Transcript 总是创建 UTF-8 文件 BOM,但请参阅下面关于-Append 的注释。

将命令追加到现有文件:

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

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

Out-File -Append / >>Add-Content 之间的这种不一致也会影响 PowerShell Core,在 this GitHub issue 中进行了讨论。

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,但默认为可能有损的 ASCII 编码,如果没有。


读取的Cmdlet(即在没有BOM时使用的编码):

Get-ContentImport-PowerShellDataFile默认为ANSI(Default),与Set-Content一致。 ANSI 也是 PowerShell 引擎在从文件中读取源代码时的默认设置。

相比之下,Import-CsvImport-CliXmlSelect-String 在没有 BOM 的情况下采用 UTF-8。

【讨论】:

有什么方法可以强制在 Win10 上不添加 te BOM? @Mvorisek:在 Windows PowerShell 中,您不能 - 您必须滚动自己的输出函数 - 请参阅 ***.com/a/34969243/45375。在 PowerShell Core(也在 Windows 上)中,无 BOM 是默认设置。 我不反对,@EliaWeiss,但它专门针对 Windows PowerShell,他们最终在 PowerShell Core 中做到了。 @Marc:VS Code 和其他现代跨平台编辑器值得称赞的是默认为 UTF-8,但这意味着它们会误解 ANSI 编码的文件。记事本使用启发式猜测编码。关键是它只是一个猜测,因为任何 UTF-8 编码文件也是技术上有效的 ANSI 编码文件(但反之则不然)。如果在没有 BOM 的情况下,Windows 上的所有内容都默认为 UTF-8 就好了,就像类 Unix 平台那样,但情况并非如此,尤其是在 Windows PowerShell 中,但幸运的是,现在在 PowerShell Core 中是这种情况。 要查看当前值(如果有的话),只需输入$PSDefaultParameterValues【参考方案2】:

简而言之,使用:

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

您可能希望将部分脚本放入大括号中,以便重定向一些命令的输出:


  command 1
  command 2
 | out-file -append -encoding utf8 "filename"

【讨论】:

引用问题:“可以通过将>foo.txt 语法替换为| out-file foo.txt -encoding utf8 来逐个完成,但每次都必须重复这很尴尬。”换句话说:您正是在暗示 OP 试图避免的事情。 我认为应该删除-append

以上是关于将 PowerShell 的默认输出编码更改为 UTF-8的主要内容,如果未能解决你的问题,请参考以下文章

Powershell & Lotus Notes - 将 While 循环的输出从文本更改为 XML 输出

如何将Apache的默认编码更改为UTF-8?

get-winevent:将格式文件更改为 groupby 日志名无效

Vs代码终端每次都更改为powershell [重复]

Hadoop中文编码乱码相关问题

我正在尝试将以下vbscript代码更改为PowerShell [关闭]