将 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-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:
相反,确实具有 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。
谷歌搜索 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-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。
【讨论】:
有什么方法可以强制在 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 输出