提问人:rwallace 提问时间:10/18/2016 最后编辑:mklement0rwallace 更新时间:10/19/2023 访问量:280387
将 PowerShell 的默认输出编码更改为 UTF-8
Changing PowerShell's default output encoding to 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'}
https://blogs.msdn.microsoft.com/powershell/2006/12/11/outputencoding-to-the-rescue/ 乍一看似乎应该是相关的,但随后它谈到了以 ASCII 编码的输出,这并不是实际发生的事情。$OutputEncoding
如何将 PowerShell 设置为使用 UTF-8?
答:
注意:
下一节主要适用于 Windows PowerShell。
- 有关跨平台 PowerShell Core (v6+) 版本,请参阅其后面的部分。
在这两种情况下,该信息都适用于使 PowerShell 使用 UTF-8 读取和写入文件。
- 相比之下,有关如何向外部程序发送和接收 UTF-8 编码字符串的信息,请参阅此答案。
现在(从最新版本的 Windows 10 开始)可以全系统切换到 UTF-8:请参阅此答案,但请注意以下注意事项:
- 该功能具有深远的影响,因为 OEM 和 ANSI 代码页都设置为 ,即 UTF-8;此外,在撰写本文时,该功能仍被视为测试版功能(Windows 11 22H2)。
65001
- 在 Windows PowerShell 中,这仅对默认为 ANSI 代码页的 cmdlet 生效,特别是 ,但不是 / ,并且它也适用于读取文件,特别是包括 PowerShell 本身读取源代码的方式。
Set-Content
Out-File
>
Get-Content
- 该功能具有深远的影响,因为 OEM 和 ANSI 代码页都设置为 ,即 UTF-8;此外,在撰写本文时,该功能仍被视为测试版功能(Windows 11 22H2)。
Windows PowerShell 透视图:
在 PSv5.1 或更高版本中,其中 和 是 的有效别名,您可以通过
$PSDefaultParameterValues
首选项变量设置>
/>>
/Out-File
的默认编码:>
>>
Out-File
在 PSv5.0 或更低版本中,您无法更改
>
/>>
的编码,但在 PSv3 或更高版本上,上述技术确实适用于对Out-File
的显式调用。
(首选项变量是在 PSv3.0 中引入的)。$PSDefaultParameterValues
在 PSv3.0 或更高版本中,如果要为支持
-Encoding
参数(在 PSv5.1+ 中包括 和 )的所有 cmdlet 设置默认编码,请使用:>
>>
$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 现在是跨平台的,通过其 PowerShell Core 版本,其编码 - 明智地 - 默认为无 BOM 的 UTF-8,与类 Unix 平台一致。
这意味着没有 BOM 的源代码文件假定为 UTF-8,使用 / / 默认为无 BOM 的 UTF-8;显式使用该参数也会创建无 BOM 的 UTF-8,但您可以选择使用带有值的伪 BOM 创建文件。
>
Out-File
Set-Content
utf8
-Encoding
utf8bom
如果在类 Unix 平台上使用编辑器创建 PowerShell 脚本,现在甚至在 Windows 上使用跨平台编辑器(如 Visual Studio Code 和 Sublime Text)创建 PowerShell 脚本,则生成的文件通常没有 UTF-8 伪 BOM:
*.ps1
- 这在 PowerShell Core 上工作正常。
- 如果文件包含非 ASCII 字符,它可能会在 Windows PowerShell 上中断;如果确实需要在脚本中使用非 ASCII 字符,请使用 BOM 将其保存为 UTF-8。
如果没有 BOM,Windows PowerShell(错误地)会将您的脚本解释为在旧版“ANSI”代码页中编码(由之前 Unicode 应用程序的系统区域设置确定;例如,美国英语系统上的 Windows-1252)。
相反,具有 UTF-8 伪 BOM 的文件在类 Unix 平台上可能会出现问题,因为它们会导致 Unix 实用程序(如 、 和 )甚至某些编辑器(如 )传递伪 BOM,即将其视为数据。
cat
sed
awk
gedit
- 这可能并不总是一个问题,但肯定是一个问题,例如当您尝试将文件读入字符串时,例如,或者 - 生成的变量将包含伪 BOM 作为前 3 个字节。
bash
text=$(cat file)
text=$(<file)
- 这可能并不总是一个问题,但肯定是一个问题,例如当您尝试将文件读入字符串时,例如,或者 - 生成的变量将包含伪 BOM 作为前 3 个字节。
Windows PowerShell 中的默认编码行为不一致:
遗憾的是,Windows PowerShell 中使用的默认字符编码非常不一致;如上一节所述,跨平台 PowerShell Core 版本值得称赞地结束了这一点。
注意:
以下内容并不希望涵盖所有标准 cmdlet。
现在,通过谷歌搜索 cmdlet 名称以查找其帮助主题,默认情况下会显示这些主题的 PowerShell Core 版本;使用左侧主题列表上方的“版本”下拉列表切换到 Windows PowerShell 版本。
从历史上看,文档经常错误地声称 ASCII 是 Windows PowerShell 中的默认编码;幸运的是,这已经得到了纠正。
写入以下内容的 Cmdlet:
Out-File
和 / 创建“Unicode” - UTF-16LE - 默认情况下的文件 - 其中每个 ASCII 范围的字符 (too) 都由 2 个字节表示 - 这与 / 显着不同(见下一点); 并创建 UTF-16LE 文件。>
>>
Set-Content
Add-Content
New-ModuleManifest
Export-CliXml
Set-Content
(如果文件尚不存在/为空)使用 ANSI 编码 (由活动系统区域设置的 ANSI 旧代码页指定的编码,PowerShell 调用)。Add-Content
Default
Export-Csv
确实创建了 ASCII 文件,如上所述,但请参阅下面的注释。-Append
Export-PSSession
默认情况下,使用 BOM 创建 UTF-8 文件。
New-Item -Type File -Value
当前创建 BOM-less(!)UTF-8 格式。
帮助主题还声称 ASCII 编码是默认的 - 我没有亲自验证过这一说法。Send-MailMessage
Start-Transcript
总是使用 BOM 创建 UTF-8 文件,但请参阅下面的注释。-Append
追加到现有文件的 Re 命令:
>>
/ Out-File -Append
不要尝试匹配文件现有内容的编码。
也就是说,它们盲目地应用其默认编码,除非另有指示,否则 不是 的选项(除非在 PSv5.1+ 中间接通过 ,如上所示)。
简而言之:您必须知道现有文件内容的编码,并使用相同的编码进行追加。-Encoding
>>
$PSDefaultParameterValues
Add-Content
是值得称赞的例外:在没有显式参数的情况下,它会检测现有编码并自动将其应用于新内容。谢谢,js2010。请注意,在 Windows PowerShell 中,这意味着如果现有内容没有 BOM,则应用的是 ANSI 编码,而在 PowerShell Core 中则为 UTF-8。-Encoding
GitHub 问题 #9423 中讨论了 / 和 之间的这种不一致,这也会影响 PowerShell Core。Out-File -Append
>>
Add-Content
Export-Csv -Append
部分匹配现有编码:如果现有文件的编码是 ASCII/UTF-8/ANSI 中的任何一个,它会盲目地附加 UTF-8,但正确匹配 UTF-16LE 和 UTF-16BE。
换句话说:在没有 BOM 的情况下,假设 UTF-8 是,而假设 ANSI。Export-Csv -Append
Add-Content
Start-Transcript -Append
部分匹配现有编码:它正确地将编码与 BOM 匹配,但在没有编码的情况下默认为可能有损的 ASCII 编码。
读取的 Cmdlet(即在没有 BOM 的情况下使用的编码):
Get-Content
并默认为 ANSI (),这与 .
ANSI 也是 PowerShell 引擎本身在从文件中读取源代码时默认使用的 ANSI。Import-PowerShellDataFile
Default
Set-Content
相反,在没有 BOM 的情况下,假定为 UTF-8,语句及其参数也是如此。Import-Csv
Import-CliXml
Select-String
switch
-File
评论
$PSDefaultParameterValues
简而言之,请使用:
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
-append
在 Windows 上使用 PowerShell 和输出重定向进行的转储将创建具有 UTF-16 编码的文件。若要解决此问题,可以尝试:
mysqldump.exe [options] --result-file=dump.sql
参考链接: mysqldump_result-file
评论