powershell replace newline eol

Reemplace CRLF usando powershell



replace newline (5)

Nota del editor : A juzgar por los comentarios posteriores del OP, lo esencial de esta pregunta es: ¿Cómo puede convertir un archivo con terminaciones de línea CRLF (estilo Windows) en un archivo solo LF (estilo Unix) en PowerShell?

Aquí está mi script de 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

Con este código puedo reemplazar 2 por 3, 1 por 7 y 9 por una cadena vacía. No puedo reemplazar el avance de línea de retorno de carro solo con el avance de línea. Pero esto no funciona.


Esta es una respuesta de estado de la unión a partir de Windows PowerShell v5.1 / PowerShell Core v6.0.1 :

  • La desafortunada respuesta de Andrew Savinykh , a pesar de ser la aceptada, es, en el momento de la redacción de este documento, fundamentalmente defectuosa (espero que se solucione, hay suficiente información en los comentarios, y en el historial de edición, para hacerlo).

  • La respuesta útil de Ansgar Wiecher funciona bien , pero requiere el uso directo de .NET Framework (y lee todo el archivo en la memoria, aunque eso podría modificarse). El uso directo de .NET Framework no es un problema en sí, sino que es más difícil de dominar para los principiantes y, en general, difícil de recordar.

  • Una versión futura de PowerShell Core (vigente a partir de este escrito: v6.1.0) tendrá una
    Convert-TextFile cmdlet Convert-TextFile con un parámetro -LineEnding para permitir la actualización en el lugar de los archivos de texto con un estilo de nueva línea específico, como se discute en GitHub .

En PSv5 + , las soluciones nativas de PowerShell ahora son posibles , porque Set-Content ahora admite el conmutador -NoNewline , que evita la adición no deseada de una nueva línea nativa de la plataforma [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

Lo anterior se basa en la capacidad de Get-Content para leer un archivo de texto que usa cualquier combinación de líneas nuevas solo CR, CRLF y LF solo línea por línea.

Advertencias :

  • Debe especificar la codificación de salida para que coincida con la del archivo de entrada para poder recrearla con la misma codificación. El comando anterior NO especifica una codificación de salida; para hacerlo, use -Encoding ; sin -Encoding :

    • En Windows PowerShell , obtendrá la codificación "ANSI" , la codificación heredada de 8 bits de un solo byte de su sistema, como Windows-1252 en sistemas de EE. UU. En inglés.
    • En PowerShell Core , obtendrá la codificación UTF-8 sin una lista de materiales .
  • El contenido del archivo de entrada, así como su copia transformada, deben caber en la memoria como un todo , lo que puede ser problemático con archivos de entrada grandes.

  • Existe el riesgo de que se dañe el archivo , si algo sale mal antes de que el nuevo contenido se pueda volver a escribir (completamente) en el archivo de entrada.

[1] De hecho, si hay varias cadenas para escribir, -NoNewline tampoco coloca una nueva línea entre ellas; en el caso que nos ocupa, sin embargo, esto es irrelevante, porque solo se escribe una cadena.


Los siguientes podrán procesar archivos muy grandes rápidamente.

$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.'')


No ha especificado la versión, supongo que está utilizando Powershell v3.

Prueba esto:

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

Nota del editor : como mike z señala en los comentarios, Set-Content agrega un CRLF al final, que no es deseado . Verificar con: ''hi'' > t.txt; (Get-Content -Raw t.txt).Replace("`r`n","`n") | Set-Content t.txt; (Get-Content -Raw t.txt).EndsWith("`r`n") ''hi'' > t.txt; (Get-Content -Raw t.txt).Replace("`r`n","`n") | Set-Content t.txt; (Get-Content -Raw t.txt).EndsWith("`r`n") ''hi'' > t.txt; (Get-Content -Raw t.txt).Replace("`r`n","`n") | Set-Content t.txt; (Get-Content -Raw t.txt).EndsWith("`r`n") , que produce $True .

Tenga en cuenta que esto carga todo el archivo en la memoria, por lo que es posible que desee una solución diferente si desea procesar grandes archivos.

ACTUALIZAR

Esto podría funcionar para v2 (lo siento en ninguna parte para probar):

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

Nota del editor : tenga en cuenta que esta solución (ahora) escribe en un archivo diferente y, por lo tanto, no es equivalente a la solución v3 (aún defectuosa). (En los comentarios se señala un archivo diferente para evitar la trampa que señala Ansgar Wiechers: usar > trunca el archivo de destino antes de que comience la ejecución). Sin embargo, lo más importante es que esta solución también agrega un CRLF final, que no es deseado . Verificar con ''hi'' > t.txt; (Get-Content t.txt) -join "`n" > t.NEW.txt; [io.file]::ReadAllText((Convert-Path t.NEW.txt)).endswith("`r`n") ''hi'' > t.txt; (Get-Content t.txt) -join "`n" > t.NEW.txt; [io.file]::ReadAllText((Convert-Path t.NEW.txt)).endswith("`r`n") ''hi'' > t.txt; (Get-Content t.txt) -join "`n" > t.NEW.txt; [io.file]::ReadAllText((Convert-Path t.NEW.txt)).endswith("`r`n") , que produce $True .

Sin embargo, la misma reserva sobre la carga en la memoria.


Solución alternativa que no añadirá un CR-LF espurio:

$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)


Agregando otra versión basada en el ejemplo anterior por @ ricky89 y @ mklement0 con algunas mejoras:

Script a procesar:

  • * .txt archivos en la carpeta actual
  • reemplazar LF con CRLF (Unix a Windows-finales de línea)
  • guardar los archivos resultantes en la subcarpeta CR-to-CRLF
  • probado en archivos de 100MB +, PS v5;

LF a 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.'') }