【问题标题】:Why are all newlines gone after PowerShell's Get-Content, Regex, and Set-Content?为什么在 PowerShell 的 Get-Content、Regex 和 Set-Content 之后所有换行符都消失了?
【发布时间】:2018-05-10 18:58:03
【问题描述】:

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

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

输入文件(模板文件)具有 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)错误行尾?

【问题讨论】:

    标签: powershell newline


    【解决方案1】:

    我认为您需要将-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是一个动态参数, 它仅在文件系统驱动器中可用。

    【讨论】:

    • 如果你这样做Get-Help -Name 'Get-Content' -Parameter 'Raw',你会发现确实如此。
    【解决方案2】:

    对于$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)
    

    注意事项:

    【讨论】:

    • 这个解决方案解决了“缺少换行的情况”。 但是我现在拥有所有 CR LF 而不仅仅是 'LF',这会使 UNIX 系统在执行脚本时失败。模板中的换行符肯定只是LF。请你扩大你的答案吗?
    • 嗯?如果您使用-Raw,您不应该处于这种情况。
    • 是的,我已经修改了很多答案,因为我自己对空格来源的假设是错误的。
    【解决方案3】:

    使用 -delimiter "`n" 选项代替 -raw-raw 选项将整个内容作为单个字符串读取/返回,尽管它保留了换行符,但如果您需要操作内容,例如跳过标题/第一行或跳过空白行等。

    获取内容 - 背景信息:

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

    Get-Content $inputFile | Set-Content $outputFilePath 
    

    但是,如果您将整个内容(读取)存储到 $variable 中,您将收到一个没有任何分隔符/分隔符的单个字符串数组(默认情况下),这意味着您会丢失换行符,但是,当读取文件(使用Get-Content)可以使用-delimiter选项指定换行符,例如:

    Get-Content -Delimiter "`n" $fileToRead
    

    HTH。

    【讨论】:

      【解决方案4】:

      我使用的是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)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-04-18
        • 2014-08-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多