1

我想做这个 :

$content = get-content "test.html"
$template = get-content "template.html"
$template | out-file "out.html"

其中 template.html 包含

<html>
  <head>
  </head>
  <body>
    $content
  </body>
</html>

和 test.html 包含:

<h1>Test Expand</h1>
<div>Hello</div>

我在 out.html 的前 2 个字符中得到了奇怪的字符:

    ��

并且内容没有展开。

如何解决这个问题?

4

2 回答 2

3

对于“奇怪的字符”,它们可能是 BOM(字节顺序标记)。-Encoding使用时使用参数显式指定输出编码Out-File,例如:

$Template |Out-File out.html -Encoding UTF8

对于字符串扩展,您需要明确告诉 powershell 这样做:

$Template = $Template |ForEach-Object {
    $ExecutionContext.InvokeCommand.ExpandString($_)
}
$Template | Out-File out.html -Encoding UTF8
于 2017-03-01T16:33:12.857 回答
3

用以下解决方案补充Mathias R. Jessen 的有用答案

  • 效率更高。
  • 确保输入文件被读取为 UTF-8,即使它们没有(伪)BOM(字节顺序标记)
  • 通过编写没有伪 BOM的 UTF-8 编码输出文件,完全避免了“奇怪的字符”问题。
# Explicitly read the input files as UTF-8, as a whole.
$content =  get-content -raw -encoding utf8 test.html
$template = get-content -raw -encoding utf8 template.html

# Write to output file using UTF-8 encoding *without a BOM*.
[IO.File]::WriteAllText(
  "$PWD/out.html",
  $ExecutionContext.InvokeCommand.ExpandString($template)
)
  • get-content -raw(PSv3+) 将文件作为一个整体读入单个字符串(而不是字符串数组,逐行),虽然更占用内存,但速度更快。对于 HTML 文件,内存使用不应该成为问题。

    • 完整读取文件的另一个优点是,如果模板包含多行子表达式 ( $(...)),则扩展仍然可以正常工作。
  • get-content -encoding utf8确保输入文件被解释为使用字符编码 UTF-8,这在当今的网络世界中很常见。

    • 这是至关重要的,因为UTF-8 编码的 HTML 文件通常没有PowerShell 需要的 3 字节伪 BOM,以便正确地将文件识别为 UTF-8 编码(见下文)。
  • 一次$ExecutionContext.InvokeCommand.ExpandString()调用就足以执行模板扩展。

  • Out-File -Encoding utf8总是会创建一个带有伪 BOM 的文件,这是不受欢迎的。
    取而代之的[IO.File]::WriteAllText()是,利用 .NET Framework默认创建没有BOM的 UTF-8 编码文件这一事实。

    • 注意$PWD/before的使用out.html,这是确保文件写入PowerShell的当前位置(目录)所必需的;不幸的是,.NET Framework 认为当前目录与 PowerShell同步。

最后,强制性安全警告:仅在您信任的输入上使用此扩展技术,因为可能会执行任意嵌入式命令。


可选的背景信息

PowerShell 的Out-File,>并默认>>使用带有BOM(字节顺序标记)的UTF-16 LE 字符编码(如前所述,“奇怪的字符”)。

虽然Out-File -Encoding utf8允许创建 UTF-8 输出文件,但
PowerShell总是在输出文件前添加一个 3 字节的伪 BOM,一些实用程序,尤其是那些具有 Unix 传统的实用程序存在问题 - 所以仍然会得到“奇怪的字符”(尽管不同的)。

如果您想要一种更类似于 PowerShell 的方式来创建无 BOM 的 UTF-8 文件,请参阅我的这个答案,它定义了一个Out-FileUtf8NoBom函数,该函数以其他方式模拟Out-File.

相反,读取文件时,您必须使用Get-Content -Encoding utf8确保无 BOM 的 UTF-8 文件被识别为此类文件。
在没有 UTF-8 伪 BOM 的情况下,Get-Content假定文件使用系统的旧代码页指定的单字节扩展 ASCII 编码(例如,英语系统上的Windows-1252Default ,PowerShell 调用的编码) .

请注意,虽然仅 Windows 的编辑器(例如记事本)使用伪 BOM 创建 UTF-8 文件(如果您明确选择保存为 UTF-8;默认为旧代码页编码“ANSI”),但越来越流行的跨平台编辑器例如Visual Studio CodeAtomSublime Text在创建文件时默认使用伪 BOM。

于 2017-03-01T16:47:47.973 回答