我有一个小的PowerShell脚本,它使用UTF8编码读取文档,在其中进行一些替换并将其保存回来,如下所示:
(Get-Content $path) -Replace "myregex","replacement" | Set-Content $path2 -Encoding utf8
这将创建一个具有正确编码和正确内容的新文件,但最后还有其他新行字符。根据{{3}}和其他许多人的说法,我被告知要么:
-NoNewLine
添加到Set-Content
[System.IO.File]::WriteAllText($path2,$content,[System.Text.Encoding]::UTF8)
两种解决方案都会移除尾随的新行... 以及文件中的所有其他新行。
有没有办法两个:
答案 0 :(得分:3)
[IO.File]::WriteAllText()
假设$content
是单个字符串,但Get-Content
生成一个字符串数组(并从每个行/字符串的末尾删除换行符)。将字符串数组迁移到单个字符串中使用$OFS
字符连接字符串(请参阅here)。
要避免此行为,您需要确保$content
在传递给WriteAllText()
时已经是单个字符串。有多种方法可以做到这一点,例如:
使用Get-Content -Raw
(PowerShell v3或更高版本):
$content = (Get-Content $path -Raw) -replace 'myregex', 'replacement'
通过Out-String
:
$content = (Get-Content $path | Out-String) -replace 'myregex', 'replacement' -replace '\r\n$'
但请注意,Out-String
(就像Set-Content
)会添加一个尾随换行符,正如评论中所指出的那样。您需要通过第二次更换操作将其删除。
使用-join
运算符加入数组:
$content = (Get-Content $path) -replace 'myregex', 'replacement' -join "`r`n"
答案 1 :(得分:3)
补充Ansgar Wiechers' helpful answer:
使用 Set-Content -NoNewline
(PSv5 +)是一个选项,但前提是您将输出作为带有嵌入换行符的单字符串传递,Get-Content -Raw
可以做到:
(Get-Content -Raw $path) -replace 'myregex', 'replacement' |
Set-Content -NoNewline $path2 -Encoding utf8
但请注意-replace
的语义随-Raw
的变化而变化:现在是单
对{em>多行字符串(整个文件内容)执行-replace
操作 - 而不是使用数组作为LHS的行个别操作。< / p>
另请注意,-Raw
将保留输入的尾随换行或无状态。
如果你想要逐行语义和/或想要确保输出的最后一行没有尾随换行符(即使输入文件只有一行),请使用Get-Content
而不{ {1}},然后-Raw
:
-join
以上在输出中使用适合平台的换行符,但请注意,输入文件不能保证使用相同的字符。
至于您尝试的内容:
正如您所观察到的那样,带有数组字符串的 (Get-Content $path) -replace 'myregex', 'replacement' -join [Environment]::NewLine |
Set-Content -NoNewline $path2 -Encoding utf8
会导致所有字符串连接而没有分隔符 - 与预期的不同,Set-Content -NoNewline
并不会省略尾随换行符:
-NoNewline
注意:输入字符串中的换行符 embedded 会被保留。
> 'one', 'two' | Set-Content -NoNewline t.txt; Get-Content -Raw t.txt
onetwo # Strings were directly concatenated.
方法导致任何换行符的原因不同,正如Ansgar的回答中所述。