ChatGPT解决这个技术问题 Extra ChatGPT

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

默认情况下,当您将命令的输出重定向到文件或将其通过管道传输到 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'} 设置输出编码,但我试过了,没有效果。

谈到 $OutputEncodinghttps://blogs.msdn.microsoft.com/powershell/2006/12/11/outputencoding-to-the-rescue/ 乍一看似乎应该是相关的,但随后它谈到了以 ASCII 编码的输出,这并不是实际发生的事情。

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


m
mklement0

笔记:

下一部分主要适用于 Windows PowerShell。有关跨平台 PowerShell Core (v6+) 版本,请参阅其后面的部分。

有关跨平台 PowerShell Core (v6+) 版本,请参阅其后面的部分。

在这两种情况下,这些信息都适用于使 PowerShell 使用 UTF-8 来读取和写入文件。相比之下,有关如何与外部程序发送和接收 UTF-8 编码字符串的信息,请参阅此答案。

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

在 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”

$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”

在 Windows PowerShell(最新和最终版本为 v5.1 的旧版)中,这总是会创建带有(伪)BOM 的 UTF-8 文件。许多基于 Unix 的实用程序无法识别此 BOM(见底部);有关创建无 BOM 的 UTF-8 文件的解决方法,请参阅此帖子。

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

在 PowerShell (Core) v6+ 中,无 BOM 的 UTF-8 是默认设置(请参阅下一节),但如果您确实需要 BOM,则可以使用“utf8BOM”

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

在 PSv3.0 或更高版本中,如果要为所有支持 -Encoding 参数(在 PSv5.1+ 中包括 > 和 >>)的 cmdlet 设置默认编码,请使用:$PSDefaultParameterValues['*:Encoding'] = 'utf8'

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

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

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

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

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

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

可选阅读:跨平台视角:PowerShell Core:

PowerShell is now cross-platform,通过其 PowerShell Core 版本,其编码 - 明智地 - 默认为 BOM-less 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)。

这在 PowerShell Core 上运行良好。

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

相反,具有 UTF-8 伪 BOM 的文件在类 Unix 平台上可能会出现问题,因为它们会导致诸如 cat、sed 和 awk 之类的 Unix 实用程序——甚至是诸如 gedit 之类的一些编辑器——传递伪 BOM通过,即,将其视为数据。这可能并不总是一个问题,但绝对可以,例如当您尝试使用 text=$(cat file) 或 text=$(

这可能并不总是一个问题,但绝对可以,例如当您尝试使用 text=$(cat file) 或 text=$(

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

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

笔记:

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

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

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

写入以下内容的 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- 16LE 和 UTF-16BE。
换一种说法:在没有 BOM 的情况下,Export-Csv -Append 假定 UTF-8 是,而 Add-Content 假定 ANSI。

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

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

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

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


有什么方法可以强制不在 Win10 上预先设置 BOM?
@Mvorisek:在 Windows PowerShell 中,您不能 - 您必须滚动自己的输出函数 - 请参阅 stackoverflow.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
p
pbies

简而言之,使用:

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 应该被删除