【问题标题】:Set-Content appends a newline (line break, CRLF) at the end of my fileSet-Content 在我的文件末尾附加一个换行符(换行符,CRLF)
【发布时间】:2017-12-29 04:55:59
【问题描述】:

我的原始配置文件 (web1.config) 没有多余的行,在记事本中查看时(显示所有字符)如下所示:

 <?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.6" />
    <httpRuntime targetFramework="4.6" />
  </system.web>
  <appSettings>
    <add key="myConnectionString" value="server=localhost;database=myDb;uid=myUser;password=myPass;" />
  </appSettings>
</configuration>

现在,我需要应用脚本将我的数据库名称更改为其他名称,如下所示:

 Move-Item "web1.config" "webtemp.config"
Get-Content "webtemp.config" | ForEach-Object {$_ -replace "database=myDb;", "database=newDb;"} |Set-Content "web1.config" -Force
Remove-Item "webtemp.config"
Write-Output('Settings Changed')

因此,生成的新文件 (web1.config) 如下所示:

请注意在文件末尾添加的额外行(完全不需要) 我尝试了所有其他选项,例如: - 使用输出文件 api - 使用 .net IO 方法 System.IO.StreamWriter - 使用 -nonewline 标志(它将所有 10 行转换为单行) - 使用不同的编码选项 - 尝试将 \r\n 替换为 \r (不要再次工作,因为 set-content 总是会生成 crlf)

我正在使用 PowerShell v5.1。

【问题讨论】:

  • 如果您的问题尚未得到完全解答,请考虑 accepting 提供答案或提供反馈。

标签: powershell newline powershell-5.0


【解决方案1】:

tl;drPSv5+;旧版本见底部):

(Get-Content webtemp.config) -replace 'database=myDb;', 'database=newDb;' -join "`n" |
  Set-Content -NoNewline -Force web1.config

注意:如果您想要 Windows 样式的 CRLF 行结尾而不是 Unix 样式的 LF-only 行结尾(PowerShell 和许多实用程序都可以处理这两者),请将 "`n" 替换为 "`r`n"


PSv5+ 中,Set-Content 支持 -NoNewline 开关,它指示 Set-Content 在每次输入后不要添加换行符(换行符)对象。这同样适用于 Add-ContentOut-File cmdlet。

换句话说:Set-Content -NoNewline直接连接所有其输入对象的字符串表示

PS> 'one', 'two' | Set-Content -NoNewline tmp.txt; Get-Content tmp.txt
onetwo

如果您传递给Set-Content -NoNewline 的是一个单个字符串已经嵌入了换行符,您可以按原样使用它并获得所需的结果:

PS> "one`ntwo" | Set-Content -NoNewline tmp.txt; "$(Get-Content -Raw tmp.txt)?"
one
two?

请注意,Get-Content -Raw按原样读取整个文件(除了字符解码),? 直接出现在two 之后这一事实意味着该文件具有没有尾随换行符。

在你的情况下,因为你正在处理输入行 一个接一个(通过Get-Content 没有 -Raw),因此输出一个 array 行(字符串),您必须首先用换行符将它们连接起来作为 分隔符 - 仅在行之间 - 并传递结果至Set-Content -NoNewline,如上图所示;这是一个简化的例子:

PS> ('one', 'two') -join "`n" | Set-Content -NoNewline tmp.txt; "$(Get-Content -Raw tmp.txt)?"
one
two?

'one', 'two' 是一个二元素字符串数组,可替代您的逐行处理命令。

编码说明:

在 Windows PowerShell 中,Set-Content 默认根据您系统的旧版单字节代码页生成“ANSI”编码文件。
要显式控制编码,请使用-Encoding 参数。


PSv4-中,需要使用.NET Framework的解决方案:

PS> [System.IO.File]::WriteAllText('tmp.txt', ('one', 'two') -join "`n"); "$(Get-Content -Raw tmp.txt)?"
one
two?

请注意,[System.IO.File]::WriteAllText() 在没有编码参数的情况下,默认为无 BOM 的 UTF-8。
根据需要将所需的[System.Text.Encoding] 编码实例作为第三个参数传递。

【讨论】:

    【解决方案2】:

    我从来没有注意到这一点,所以我快速搜索并发现:

    set-content adds newlines by default

    建议的解决方案是将您的内容编码为字节,然后使用带有 -Encoding 参数的 Set-Content。

    Set-Content test.txt ([byte[]][char[]] "test") -Encoding Byte
    

    我自己测试过,所以我可以确认它有效。

    【讨论】:

    • 很好的发现/回答 +1。顺便提一下,这在 Linux/Darwin 上的 PowerShell 6.0.0beta4 上同样有效,除了仅附加 lf 0A
    • 这个解决方案有一个警告:它本质上创建了一个单字节的 ISO-8859-1 编码文件(ISO-8859-1 在很大程度上与最广泛使用的旧版 Windows 兼容,但并不完全兼容代码页,Windows-1252),这意味着 (a) 您不能选择不同的输出编码,并且 (b) 解决方案会中断包含不属于 ISO-8859-1 的字符的字符串,例如 @987654324 @:以下命令breaks,例如:Set-Content test.txt ([byte[]][char[]] "€") -Encoding Byte
    • @LotPings:此解决方案不附加 anything,这就是重点(相比之下,输入中已经存在的任何换行符都是在 Unix 平台上可能是 LF-only)。但是,如上所述,从编码的角度来看,这种解决方案是有问题的。
    • @mklement0 不吉利的措辞,区别只是系统特定的行终止。
    【解决方案3】:

    我看到这是一个 xml 文件。这种方式不会添加换行符。

    [xml]$xml = get-content web1.config
    $xml.configuration.appSettings.add.value = 
      $xml.configuration.appSettings.add.value -replace 'database=myDb;',
      'database=newDb;'
    $xml.save("$pwd\web1.config")  # in case of .net weirdness
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-28
      • 2020-08-25
      • 1970-01-01
      • 2013-03-16
      相关资源
      最近更新 更多