注意:
-
在PSv5.1或更高版本中,>和>>实际上是Out-File的别名,您可以为>/>>设置默认编码/Out-File 通过$PSDefaultParameterValues 偏好变量:
$PSDefaultParameterValues['Out-File:Encoding'] = 'utf8'
- 注意:
-
在 PSv5.0 或更低版本中,您无法更改 > / >> 的编码,但是,在 >PSv3 或更高版本,上述技术确实适用于显式调用 Out-File。
($PSDefaultParameterValues 首选项变量是在 PSv3.0 中引入的)。
-
在 PSv3.0 或更高版本中,如果您想为所有支持
的 cmdlet 设置默认编码
-Encoding 参数(在 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 用于保存到文件的编码无关。
选读:跨平台视角: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 实用程序,例如 cat、sed 和 @987654365 @ - 甚至一些编辑器如gedit - 通过传递伪BOM,即把它当作数据。
- 这可能并不总是成为问题,但绝对可能是,例如当您尝试使用
text=$(cat file) 或text=$(<file) 将文件读入bash 中的字符串时- 结果变量将包含伪 BOM 作为前 3 个字节。
Windows PowerShell 中的默认编码行为不一致:
很遗憾,Windows PowerShell 中使用的默认字符编码非常不一致;正如上一节所讨论的,跨平台的 PowerShell Core 版本已经很好地结束了这一点。
注意:
编写的 Cmdlet:
Out-File 和 > / >> 创建“Unicode” - UTF-16LE - 默认文件 - 其中每个 ASCII 范围字符(也)由 2 个字节表示 -这与Set-Content / Add-Content 明显不同(见下一点); New-ModuleManifest 和 Export-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-Content和Import-PowerShellDataFile默认为ANSI(Default),与Set-Content一致。
ANSI 也是 PowerShell 引擎在从文件中读取源代码时的默认设置。
相比之下,Import-Csv、Import-CliXml 和 Select-String 在没有 BOM 的情况下采用 UTF-8。