使用powershell替换CRLF

时间:2013-10-01 23:35:47

标签: powershell replace newline eol

编者注::根据OP后来的评论判断,这个问题的要点是: 如何将具有CRLF(Windows风格)行结尾的文件转换为PowerShell中的仅LF(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

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

7 个答案:

答案 0 :(得分:26)

您尚未指定版本,我假设您使用的是Powershell v3。

试试这个:

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

编辑注释:正如mike z在评论中指出的那样, 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

请注意,这会将整个文件加载到内存中,因此如果要处理大文件,可能需要使用其他解决方案。

<强>更新

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

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

编者注::请注意,此解决方案(现在)会写入不同的文件,因此不等同于(仍有缺陷的)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

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

答案 1 :(得分:20)

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

  • Andrew Savinykh's ill-fated answer,尽管是被接受的,但是,在撰写本文时,基本上存在缺陷(我希望它得到修复 - 那里有足够的信息)评论 - 以及在编辑历史中 - 这样做。)

  • Ansgar Wiecher's helpful answer 效果很好,但需要直接使用.NET Framework (并将整个文件读入内存,尽管可能是改变)。直接使用.NET Framework本身并不是问题,但是对于新手而言难以掌握并且难以记住。

  • 未来版本的PowerShell Core 将有一个
    Convert-TextFile cmdlet -LineEnding cmdlet,允许使用特定的换行符样式就地更新文本文件,如on GitHub所述。

PSv5 + 中,现在可以使用PowerShell原生解决方案,因为Set-Content现在支持-NoNewline切换,可以防止意外添加platform-native newline [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

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

<强>注意事项

  • 您需要指定输出编码匹配输入文件 ,以便使用相同的编码。上面的命令没有指定输出编码; 要执行此操作,请使用-Encoding ; 没有 -Encoding

    • Windows PowerShell 中,您将获得&#34; ANSI&#34; 编码,您的系统单字节,8位传统编码,例如美英系统上的Windows-1252。
    • PowerShell核心 中,您将获得 UTF-8编码,无需 BOM 。< / LI>
  • 输入文件的内容及其转换后的副本必须适合整个内存 ,这对于大输入文件可能会有问题

  • 如果写回输入文件的过程中断,则文件损坏风险

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

答案 2 :(得分:13)

不会附加虚假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)

答案 3 :(得分:1)

在@ ricky89和@ mklement0的基础上添加另一个基于上述示例的版本,几乎没有改进:

要处理的脚本:

  • *。当前文件夹中的txt文件
  • 用CRLF替换LF(Unix到Windows行结尾)
  • 将生成的文件保存到CR-to-CRLF子文件夹
  • 在100MB +文件上测试,PS v5;

LF至CRLF.ps1:

# get current dir
$currentDirectory = Split-Path $MyInvocation.MyCommand.Path -Parent

# create subdir CR-to-CRLF for new files
$outDir = $(Join-Path $currentDirectory "CR-to-CRLF")
New-Item -ItemType Directory -Force -Path $outDir | Out-Null

# get all .txt files
Get-ChildItem $currentDirectory -Force | Where-Object {$_.extension -eq ".txt"} | ForEach-Object {
  $file = New-Object System.IO.StreamReader -Arg $_.FullName
  # Resulting file will be in CR-to-CRLF subdir
  $outstream = [System.IO.StreamWriter] $(Join-Path  $outDir $($_.BaseName + $_.Extension))
  $count = 0 
  # read line by line, replace CR with CRLF in each by saving it with $outstream.WriteLine
  while ($line = $file.ReadLine()) {
        $count += 1
        $outstream.WriteLine($line)
    }
  $file.close()
  $outstream.close()
  Write-Host ("$_`: " + $count + ' lines processed.')
}

答案 4 :(得分:1)

下面是我的脚本,用于递归转换所有文件。您可以指定要排除的文件夹或文件。

$excludeFolders = "node_modules|dist|.vs";
$excludeFiles = ".*\.map.*|.*\.zip|.*\.png|.*\.ps1"

Function Dos2Unix {
    [CmdletBinding()]
    Param([Parameter(ValueFromPipeline)] $fileName)

    Write-Host -Nonewline "."

    $fileContents = Get-Content -raw $fileName
    $containsCrLf = $fileContents | %{$_ -match "\r\n"}
    If($containsCrLf -contains $true)
    {
        Write-Host "`r`nCleaing file: $fileName"
        set-content -Nonewline -Encoding utf8 $fileName ($fileContents -replace "`r`n","`n")
    }
}

Get-Childitem -File "." -Recurse |
Where-Object {$_.PSParentPath -notmatch $excludeFolders} |
Where-Object {$_.PSPath -notmatch $excludeFiles} |
foreach { $_.PSPath | Dos2Unix }

答案 5 :(得分:0)

以下内容可以快速处理非常大的文件。

$file = New-Object System.IO.StreamReader -Arg "file1.txt"
$outstream = [System.IO.StreamWriter] "file2.txt"
$count = 0 

while ($line = $file.ReadLine()) {
      $count += 1
      $s = $line -replace "`n", "`r`n"
      $outstream.WriteLine($s)
  }

$file.close()
$outstream.close()

Write-Host ([string] $count + ' lines have been processed.')

答案 6 :(得分:0)

对于CMD,仅适用于LF的一行:

powershell -NoProfile -command "((Get-Content 'prueba1.txt') -join \"`n\") + \"`n\" | Set-Content -NoNewline 'prueba1.txt'"

因此您可以创建一个.bat