如何在PowerShell中为herestring / heredoc设置编码?

5

我正在尝试使用 PowerShell 中的 heredoc 更新 Windows 服务器上的主机文件。

我无法弄清楚为什么我的结果在每个主机条目中的每个字符之间都有额外的空格。

我正在从 Linux 迁移一些脚本。

PS C:\Users\Administrator> cat C:\Users\Administrator\AppData\Local\Temp\etchosts.ps1
@"
127.0.0.1 src.example.com
127.0.0.2 builds.example.com
127.0.0.3 ti.example.com
127.0.0.4 jira.example.com
"@ >>C:\Windows\System32\drivers\etc\hosts



PS C:\Users\Administrator> powershell C:\Users\Administrator\AppData\Local\Temp\etchosts.ps1
PS C:\Users\Administrator> cat C:\Windows\System32\drivers\etc\hosts
# Copyright (c) 1993-2009 Microsoft Corp.
#
# This is a sample HOSTS file used by Microsoft TCP/IP for Windows.
#
# This file contains the mappings of IP addresses to host names. Each
# entry should be kept on an individual line. The IP address should
# be placed in the first column followed by the corresponding host name.
# The IP address and the host name should be separated by at least one
# space.
#
# Additionally, comments (such as these) may be inserted on individual
# lines or following the machine name denoted by a '#' symbol.
#
# For example:
#
#      102.54.94.97     rhino.acme.com          # source server
#       38.25.63.10     x.acme.com              # x client host

# localhost name resolution is handled within DNS itself.
#       127.0.0.1       localhost
#       ::1             localhost
 1 2 7 . 0 . 0 . 1   s r c . e x a m p l e . c o m

 1 2 7 . 0 . 0 . 2   b u i l d s . e x a m p l e . c o m

 1 2 7 . 0 . 0 . 3   t i . e x a m p l e . c o m

 1 2 7 . 0 . 0 . 4   j i r a . e x a m p l e . c o m

我希望所有字符之间没有空格。如果有一种“Windows”方式可以做到这一点,我将非常感激任何输入/建议。


1
>> -> | Out-File -Encoding ASCII -Append - user4003407
2个回答

7

Here-String是PowerShell字符串文字的一种特殊形式,就像PowerShell和.NET(System.String)中的所有字符串一样,在内存中的编码始终为UTF-16。

  • 顺便说一下:为了正确地将字符串文字读入内存,封闭的脚本文件必须被正确编码;最好选择带有BOM的UTF-8 - 请参见此答案

然而,重要的是如何将(内存中的)字符串写入文件

>> file 实际上与 | Out-File -Append file 相同,在 Windows PowerShell 中,Out-File 的默认编码为 UTF16-LE(“Unicode”),其中每个字符通常使用 2 个字节 编码。看起来像空格的实际上是每个 ASCII 范围字符编码的第二个字节中的 NUL (0x0) 字节。

  • 顺便说一下:在 PowerShell Core 中,默认情况下为无 BOM 的 UTF-8 编码,这更加合理;由于 UTF-8 兼容 ASCII 范围内的字符,因此您的代码在 PowerShell Core 中可以正常工作。

相比之下,C:\Windows\System32\drivers\etc\hosts 使用 ASCII 编码(每个字符占用 1 个字节)。

为了匹配该编码,请使用 Add-Content 替代 >>

@"
127.0.0.1 src.example.com
127.0.0.2 builds.example.com
127.0.0.3 ti.example.com
127.0.0.4 jira.example.com
"@ | Add-Content C:\Windows\System32\drivers\etc\hosts

Out-File -Append不同,Add-Content会匹配文件现有内容的编码(如果没有,则默认为Windows PowerShell中活动ANSI代码页的编码(“Default”);在没有BOM的情况下,像这种情况一样,假定为ANSI编码,但对于仅限ASCII范围的输入字符,这实际上与ASCII相同,因为ANSI代码页是ASCII的超集。

另请参阅:


我觉得我们需要把你关于编码和粘性的最佳、最详细的帖子拿出来,放在某个地方。这个问题经常出现。 - AdminOfThings
谢谢,@AdminOfThings。理想情况下,官方文档应该提供这些信息,并且有一个开放的建议添加。与此同时,这个答案可能提供了最全面的概述。 - mklement0
谢谢。这真的很有帮助。我本来要安装wsl,但由于这是一个配置aws实例的脚本,所以安装需要重新启动,这会使事情变得复杂。我有一个相关的问题。我在实例的用户数据中有这段代码:@' {{.sshconfig}} '@ >C:\ProgramData\ssh\sshd_config ... 这似乎具有正确的编码,你知道为什么吗?({{.sshconfig}}将被替换) - mikedoy
@mikedoy: 很高兴听到这个消息。如果您使用PowerShell_Core_或在Windows PowerShell v5.1中全局将>的编码更改为ASCII或ANIS(“默认”),则>C:\ProgramData\ssh\sshd_config才能按预期工作(仅限ASCII范围字符),如此答案所示。 - mklement0

1
我永远不会使用"out-file -append"或">>".它不检查当前的编码。这是PowerShell 5的一个可怕的特点。现在你有一个混合了ASCII和Unicode的文件。空格实际上是nulls。在这种情况下,我更喜欢add-content。Add-content将首先检查BOM。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接