使用powershell替换CRLF

Ang*_*Boy 26 powershell replace newline eol

编者注:根据OP后来的评论来判断,这个问题的要点是: 如何将一个带有CRLF(Windows风格)行结尾的文件转换为PowerShell中的LF-only(Unix风格)文件?

这是我的powershell脚本:

 $original_file ='C:\Users\abc\Desktop\File\abc.txt'
 (Get-Content $original_file) | Foreach-Object {
 $_ -replace "'", "2"`
-replace '2', '3'`
-replace '1', '7'`
-replace '9', ''`
-replace "`r`n",'`n'
} | Set-Content "C:\Users\abc\Desktop\File\abc.txt" -Force
Run Code Online (Sandbox Code Playgroud)

使用此代码,我可以将3替换为2,使用空字符串替换为7和9.我只能使用换行符替换回车换行符.但这不起作用.

And*_*ykh 27

你还没有指定版本,我假设你使用的是Powershell v3.

试试这个:

$path = "C:\Users\abc\Desktop\File\abc.txt"
(Get-Content $path -Raw).Replace("`r`n","`n") | Set-Content $path -Force
Run Code Online (Sandbox Code Playgroud)

编者注:正如迈克在评论中指出的那样,Set-Content追加一个尾随的CRLF,这是不受欢迎的.验证:'hi' > t.txt; (Get-Content -Raw t.txt).Replace("`r`n","`n") | Set-Content t.txt; (Get-Content -Raw t.txt).EndsWith("`r`n"),哪个产生$True.

请注意,这会将整个文件加载到内存中,因此如果要处理大文件,可能需要不同的解决方案.

UPDATE

这可能适用于v2(抱歉无处测试):

$in = "C:\Users\abc\Desktop\File\abc.txt"
$out = "C:\Users\abc\Desktop\File\abc-out.txt"
(Get-Content $in) -join "`n" > $out
Run Code Online (Sandbox Code Playgroud)

编者注:请注意,此解决方案(现在)写入不同的文件,因此不等同于(仍有缺陷的)v3解决方案.(一个不同的文件的目标是避免陷阱,Ansgar Wiechers在评论中指出:执行开始之前使用> 截断目标文件).但更重要的是:这个解决方案也附加了一个尾随的CRLF,这是不受欢迎的.验证,哪个收益率.'hi' > t.txt; (Get-Content t.txt) -join "`n" > t.NEW.txt; [io.file]::ReadAllText((Convert-Path t.NEW.txt)).endswith("`r`n")$True

关于被加载到内存的相同保留.

  • 这几乎可以奏效.`Set-Content`仍将在末尾插入额外的CR/LF. (4认同)
  • 伟大的我更新到powershell v3和你的代码工作,但它仍然像迈克提到的那样留下CR/LF.我只想要所有的LF而没有CR/LF (3认同)
  • PSv5+ 为尾随 CRLF 问题提供了解决方案:`Set-Content -NoNewline`。使用`| 可以避免使用`>` 截断输出文件。Out-File ...`(或 `| Set-Content ...`)代替。 (3认同)

mkl*_*nt0 26

从Windows PowerShell v5.1/PowerShell Core v6.0.1开始,这是一个联合状态的答案:

  • 尽管是被接受的答案,Andrew Savinykh的命运多了,但在撰写本文时,其根本上存在缺陷(我希望它得到修复 - 评论中有足够的信息 - 在编辑历史中 - 这样做).

  • Ansgar Wiecher的有用答案 很有效,但需要直接使用.NET Framework(并将整个文件读入内存,尽管可以更改).直接使用.NET Framework本身并不是问题,但是对于新手而言难以掌握并且通常难以记住.

  • 一个未来的PowerShell版本的核心(目前在写这篇文章的:6.1.0)将有一个
    Convert-TextFile小命令与-LineEnding参数,允许就地文本文件更新与特定换行符风格,正在讨论在GitHub上.

PSv5 +中,现在可以使用PowerShell原生解决方案,因为Set-Content现在支持-NoNewline切换,可以防止对平台本地换行的不希望的附加[1] :

# Convert CRLFs to LFs only.
# Note:
#  * (...) around Get-Content ensures that $file is read *in full*
#    up front, so that it is possible to write back the transformed content
#    to the same file.
#  * + "`n" ensures that the file has a *trailing LF*, which Unix platforms
#     expect.
((Get-Content $file) -join "`n") + "`n" | Set-Content -NoNewline $file
Run Code Online (Sandbox Code Playgroud)

以上内容依赖于Get-Content读取文本文件的能力,该文本文件逐行使用CR-only,CRLF和LF-only换行符的任意组合.

警告:

  • 您需要指定输出编码匹配输入文件,以便使用相同的编码重新创建它.上面的命令没有指定输出编码; 这样做,使用-Encoding ; 没有 -Encoding:

    • Windows PowerShell中,您将获得"ANSI"编码,即系统的单字节,8位传统编码,例如美国英语系统上的Windows-1252.
    • PowerShell Core中,您将获得没有 BOM的UTF-8编码.
  • 输入文件的内容及其转换后的副本必须作为一个整体适合内存,这对于大型输入文件可能会有问题.

  • 如果在将新内容(完全)写回输入文件之前出现问题,则存在文件损坏风险.


[1]实际上,如果要写多个字符串,-NoNewline也不要它们之间放置换行符; 然而,在这种情况下,这是无关紧要的,因为只写了一个字符串.


Ans*_*ers 18

替代解决方案,不会附加虚假的CR-LF:

$original_file ='C:\Users\abc\Desktop\File\abc.txt'
$text = [IO.File]::ReadAllText($original_file) -replace "`r`n", "`n"
[IO.File]::WriteAllText($original_file, $text)
Run Code Online (Sandbox Code Playgroud)

  • 做得很好(也在v2中工作).重新使用_relative_路径:使用`(Convert-Path $ original_file)`首先将相对路径转换为完整路径,因为.NET框架对当前目录的概念通常与PS不同. (2认同)
  • @Seth使用负向后断言:`` '(?!<\ r)\n', "`r`n"``(更换时如果LF不是由CR之前CR-LF LF). (2认同)