为什么PowerShell的获取内容、正则表达式和设置内容之后所有的换行符都消失了?

5ssjco0h  于 2023-03-18  发布在  Shell
关注(0)|答案(4)|浏览(152)

我想将一个文件模板加载到一个变量中,修改变量中的数据,并将修改后的模板从变量输出到一个新位置。
问题是PowerShell正在从我的模板中删除换行符。
输入文件(模板文件)具有Unix行结尾,由于修改版本的接收者是基于Unix的系统,因此输出也需要Unix行结尾。
我有以下代码,它会生成一个串联的一行程序:

[String] $replacement = "Foo Bar"
[String] $template = Get-Content -Path "$pwd\template.sh" -Encoding UTF8
$template = $template -replace '<REPLACE_ME>', $replacement
$template | Set-Content -Path "$pwd\script.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)* 错误 * 的行尾?

wixjitnu

wixjitnu1#

对于$replacement变量,您实际上不需要指定[string]类型,PowerShell将从赋值中推断该类型。
对于$template变量,[string]实际上是错误的,默认情况下,Get-Content会给予你一个字符串数组(即行),而不是一个字符串。
但实际上,你一开始就不想把输入拆分成行,当Set-ContentOut-File看到一个数组作为它们的输入时,它们会用空格把它连接起来。
使用-Raw可以使Get-Content将整个文件作为一个字符串返回,这样行结束符(如Linux文件的LF)也将保持原样。

$replacement = "Foo Bar"
$template = Get-Content -Path "$pwd\template.sh" -Encoding UTF8 -Raw
$template = $template -replace '<REPLACE_ME>', $replacement
Set-Content -Path "$pwd\script.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 "$pwd\template.sh" -Encoding UTF8 -Raw
$template = $template -replace '<REPLACE_ME>', $replacement
[System.IO.File]::WriteAllText("$pwd\script.sh", $template, $UTF8_NO_BOM)

注:

  • PowerShell操作符(如-replace)对数组执行静默操作。$x -replace "search", "replacement"将对 $x 的每个成员执行替换操作,无论是单个字符串还是它们的数组。
  • 推荐阅读:* 一个月一次 *
drkbr07n

drkbr07n2#

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

获取内容背景信息:

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

Get-Content $inputFile | Set-Content $outputFilePath

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

Get-Content -Delimiter "`n" $fileToRead

嗯。

nkoocmlb

nkoocmlb3#

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

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

要停止将Windows行尾添加到脚本末尾,我认为您需要使用以下.NET方法来编写文件:

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

默认情况下,PowerShell会尝试将您的输入转换为文件中每行的字符串数组。我认为由于Unix行尾,它没有成功地做到这一点,但随后会删除新的行字符。
在PowerShell 3.0中,我们现在有了一个新的动态参数Raw。指定后,Get-Content将忽略换行符,并在一个字符串中返回文件的全部内容。Raw是一个动态参数,仅在文件系统驱动器中可用。

vq8itlhq

vq8itlhq4#

我使用的是Get-Content-Tail,它不允许同时指定-Raw,但我确实幸运地使用了Out-String

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

或者,如果你关心尾巴:

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

相关问题