我想将文件模板加载到变量中,修改变量中的数据并将修改后的模板从变量输出到新位置。
问题是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-Content
或Out-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-Content
cmdlet 逐行读取并返回内容,这意味着如果通过管道将Set-Content
或Add-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)