如何使用PowerShell扩展文件内容

时间:2017-03-01 16:26:06

标签: powershell variable-expansion file-encodings

我想这样做:

$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 个答案:

答案 0 :(得分:3)

对于&#34;奇怪的字符&#34;,它们可能是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

答案 1 :(得分:3)

使用以下解决方案补充Mathias R. Jessen's helpful answer

  • 更有效率。
  • 确保输入文件读取为UTF-8,即使它们没有(伪 - )BOM (byte-order mark)
  • 通过编写没有伪伪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 +)将中的文件作为整体读入单字符串(而不是数组 of strings,line by line),虽然内存密集程度更高,但速度更快。对于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 默认创建UTF-8编码文件而不 BOM << /强>

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

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

可选背景信息

PowerShell的Out-File>>>默认使用UTF-16 LE字符编码BOM (byte-order mark)(如上所述,“奇怪的字符”)。

虽然 Out-File -Encoding utf8 允许创建UTF-8输出文件,但是 PowerShell 总是在输出文件中添加一个3字节的pseudo-BOM ,其中一些实用程序,特别是那些具有Unix遗产的实用程序存在问题 - 所以仍然 em>得到“奇怪的人物”(虽然不同)。

如果您希望更像PowerShell的方式来创建无BOM的UTF-8文件, 请参阅我的this answer,其中定义了一个Out-FileUtf8NoBom函数,该函数以其他方式模拟Out-File的核心功能。

相反,读取文件上,您必须使用Get-Content -Encoding utf8来确保无BOM的UTF-8文件被识别。
如果没有UTF-8伪BOM,Get-Content会假定该文件使用系统的旧版代码页指定的单字节扩展ASCII编码 (例如,英语系统上的Windows-1252,PowerShell称之为Default的编码。)

请注意,虽然仅限Windows的编辑器(如记事本)创建带有伪BOM的UTF-8文件,如果您明确选择保存为UTF-8;默认是遗留代码页编码,“ANSI”),越来越受欢迎的跨平台编辑器,例如Visual Studio CodeAtomSublime Text,默认情况下在创建文件时使用伪BOM。