为什么PowerShell的Get-Content,Regex和Set-Content之后的所有换行符都消失了?



我想将文件模板加载到变量中,修改变量中的数据并将修改后的模板从变量输出到新位置。

问题是PowerShell正在从我的模板中删除换行符。

输入文件(模板文件)具有Unix行尾,这也是输出所必需的,因为修改版本的接收者是基于Unix的系统。

我有以下代码,它会导致连接的单行:

[String] $replacement = "Foo Bar"
[String] $template = Get-Content -Path "$pwdtemplate.sh" -Encoding UTF8
$template = $template -replace '<REPLACE_ME>', $replacement
$template | Set-Content -Path "$pwdscript.sh" -Encoding UTF8

具有模板输入:

#!/bin/sh
myvar="<REPLACE_ME>"
echo "my variable: $myvar"
exit 0

结果是:

#!/bin/sh myvar="Foo Bar" echo "my variable: $myvar" exit 0

在我看来,LF某个地方被一个简单的空格所取代。最后,在脚本的末尾,有一个附加的CR LF模板文件中不存在。

如何保留行尾并防止在最终脚本中添加更多(CR LF)错误的行尾?

对于$replacement变量,你实际上不需要指定类型[string],PowerShell将从赋值中推断出来。

对于$template变量,[string]实际上是错误的。默认情况下,Get-Content会给你一个字符串数组(即行)而不是一个字符串。

但实际上,您甚至不想首先将输入拆分为行。当Set-ContentOut-File看到数组作为他们的输入时,他们将用空格连接它。

使用-Raw可以Get-Content将整个文件作为一个字符串返回,这样行尾(如 Linux 文件的LF)也将保持原样。

$replacement = "Foo Bar"
$template = Get-Content -Path "$pwdtemplate.sh" -Encoding UTF8 -Raw
$template = $template -replace '<REPLACE_ME>', $replacement
Set-Content -Path "$pwdscript.sh" -Value $template -Encoding UTF8

PowerShell将使用BOM保存所有UTF-8文件。如果您不希望这样做,则必须使用其他实用程序来写入文件:

$UTF8_NO_BOM = New-Object System.Text.UTF8Encoding $False
$replacement = "Foo Bar"
$template = Get-Content -Path "$pwdtemplate.sh" -Encoding UTF8 -Raw
$template = $template -replace '<REPLACE_ME>', $replacement
[System.IO.File]::WriteAllText("$pwdscript.sh", $template, $UTF8_NO_BOM)

笔记:

  • PowerShell运算符(如-replace)在阵列上静默操作。$x -replace "search", "replacement"将对$x的每个成员执行替换操作,无论是单个字符串还是数组。
  • 推荐阅读:PowerShell Set-Content 和 Out-File 有什么区别?

使用 -delimiter "'n">选项而不是-raw-raw选项将整个内容读取/返回为单个字符串,尽管它保留了换行符,但如果您需要操作内容(例如跳过标题/第一行或跳过空白行等),则毫无用处。

获取内容 - 背景信息:

默认情况下,Get-Contentcmdlet 逐行读取并返回内容,这意味着如果通过管道将Set-ContentAdd-Content立即将每一行(正在读取)写入输出文件 - 换行符将按预期保留和写入,例如:

Get-Content $inputFile | Set-Content $outputFilePath 

但是,如果您将整个内容(读取)存储到一个变量(称为 $variable)中,您的变量将只接收一个没有分隔符/分隔符的字符串数组(默认情况下),这意味着您将丢失换行符,但是,在读取文件(使用Get-Content)时,您可以使用-delimiter选项指定换行符 ('n),然后将其保留并写入/存储到您的$variable中, 例如:

Get-Content -Delimiter "`n" $fileToRead

呵呵。

我认为您需要将-Raw开关与Get-Content一起使用,以便将文件加载为单个字符串:

[String] $replacement = "Foo Bar"
[String] $template = Get-Content -Path "$pwdtemplate.sh" -Encoding UTF8 -Raw
$template = $template -replace '<REPLACE_ME>', $replacement

为了阻止将 Windows 行结尾添加到脚本末尾,我认为您需要使用此 .NET 方法来写入文件:

[io.file]::WriteAllText("$pwdtemplate.sh",$template)

默认情况下,PowerShell 会尝试将输入转换为文件中每一行的字符串数组。我认为由于 Unix 行结尾,它没有成功执行此操作,但随后删除了新行字符。

在PowerShell 3.0中,我们现在有一个新的动态参数Raw。什么时候 指定,获取内容忽略换行符并返回 一个字符串中文件的全部内容。Raw 是一个动态参数, 它仅在文件系统驱动器中可用。

  • https://social.technet.microsoft.com/Forums/windowsserver/en-US/6026b31a-2a0e-4e0a-90b5-355387dce9ac/preventing-newline-with-outfile-or-addcontent?forum=winserverpowershell

我使用的是Get-Content-Tail,它不允许你同时指定-Raw,但我确实很幸运Out-String.因此,在您的情况下:

$template = Out-String -InputObject $( Get-Content -Path "$pwdtemplate.sh" -Encoding UTF8 -Raw)

或者,如果你关心尾巴:

$template = Out-String -InputObject $(Get-Content -Path "$pwdtemplate.sh" -tail 4)

最新更新