Set-Content在我的文件末尾添加换行符(换行符,CRLF)

OmG*_*esh 17 powershell newline powershell-5.0

我的原始配置文件(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>
Run Code Online (Sandbox Code Playgroud)

现在,我需要应用脚本将我的数据库名称更改为其他类似的内容:

 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')
Run Code Online (Sandbox Code Playgroud)

因此,生成的新文件(web1.config)看起来像:

在此输入图像描述

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

我正在使用PowerShell v5.1.

mkl*_*nt0 19

tl; dr (PSv5 + ;参见旧版本的底部):

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

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


PSv5 +中,Set-Content支持-NoNewline切换,指示Set-Content不在每个输入对象后添加换行符(换行符).这同样适用于Add-ContentOut-Filecmdlet.

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

> 'one', 'two' | Set-Content -NoNewline tmp.txt; Get-Content tmp.txt
onetwo
Run Code Online (Sandbox Code Playgroud)

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

> "one`ntwo" | Set-Content -NoNewline tmp.txt; "$(Get-Content -Raw tmp.txt)?"
one
two?
Run Code Online (Sandbox Code Playgroud)

请注意,Get-Content -Raw原样读取文件(除了字符解码)以及?之后直接显示的事实two意味着文件没有尾随换行符.

在您的情况下,由于您逐个处理输入行(通过Get-Content 没有 -Raw)并因此输出行(字符串)数组,您必须首先使用换行符作为分隔符连接它们 - 仅在行之间 - 并将结果传递给Set-Content -NoNewline,如顶部所示; 这是一个简化的例子:

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

'one', 'two' 是一个双元素字符串数组,它是您的逐行处理命令的替身.

编码说明:

在Windows PowerShell中,Set-Content默认情况下会根据系统的传统单字节代码页生成"ANSI"编码文件.
要显式控制编码,请使用-Encoding参数.


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

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

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

  • Powershell 有一些有趣的设计决策......比如,在什么情况下有人会想要附加换行符? (3认同)

Ste*_*NLD 4

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

set-content 默认添加换行符

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

Set-Content test.txt ([byte[]][char[]] "test") -Encoding Byte
Run Code Online (Sandbox Code Playgroud)

我自己测试了它,所以我可以确认它是否有效。

  • @LotPings:这个解决方案不会附加 _anything_,这就是重点(相比之下,输入中已经存在的任何换行符在 Unix 平台上可能只是 LF)。然而,如上所述,从编码的角度来看,该解决方案是有问题的。 (2认同)