2010-05-06 28 views
5

Quiero encontrar un fragmento de texto en un archivo xml grande y quiero reemplazarlo por otro texto. El tamaño del archivo es de alrededor (50 GB). Quiero hacer esto en línea de comando. Estoy mirando Powershell y quiero saber si puede manejar el tamaño grande. También me gustaría saber la sintaxis para escapar de los operadores clave en powershell. Yo soy muy novato PowerShellBuscar y reemplazar en un archivo grande

Actualmente estoy tratando algo como esto pero no le gusta

Get-Content C:\File1.xml | Foreach-Object {$_ -replace "xmlns:xsi=\"http:\/\/www\.w3\.org\/2001\/XMLSchema-instance\"", ""} | Set-Content C:\File1.xml 

El texto quiero reemplazar es xmlns: xsi = "http: //www.w3. org/2001/XMLSchema-instance " con cadena vacía" ".

Preguntas

  1. Can PowerShell manejan grandes archivos
  2. Como llamar en el guión PowerShell desde la línea de comandos
  3. La sintaxis para escapar clave operadores en PowerShell y la lista de operadores principales en PowerShell.
  4. No deseo que la sustitución ocurra en la memoria y prefiera la transmisión suponiendo que no llevará al servidor a sus rodillas.
  5. ¿Hay otros enfoques que puedo tomar (Diferente herramientas/estrategia?)

Gracias

Respuesta

3

no le gusta porque no se puede leer desde un archivo y escribir de nuevo a él en Al mismo tiempo, usa Get-Content/Set-Content. Recomiendo usar un archivo temporal y luego al final, renombrar file1.xml a file1.xml.bak y renombrar el archivo temp a file1.xml.

  1. Sí, siempre que no intente cargar todo el archivo de una vez. Línea por línea funcionará, pero va a ser un poco lento. Use el parámetro -ReadCount y configúrelo en 1000 para mejorar el rendimiento.
  2. ¿Qué línea de comando? ¿Potencia Shell? Si es así, puede invocar su secuencia de comandos como .\myscript.ps1 y si toma los parámetros, entonces c:\users\joe\myscript.ps1 c:\temp\file1.xml.
  3. En general para las expresiones regulares, utilizaría comillas simples si no necesita hacer referencia a las variables de PowerShell. Entonces solo necesita preocuparse por el escape de expresiones regulares y no por el escape de PowerShell. Si necesita utilizar comillas dobles, el carácter de retroceso es el carácter de escape entre comillas dobles, p. Ej. "` $ p1 está configurado a $ ps1 ". En su ejemplo, las citas simples simplifican su expresión regular (nota: las barras diagonales no son metacaracteres en expresiones regulares):

    'xmlns: xsi = "http://www.w3.org/2001/XMLSchema-instance"'

  4. Absolutamente desea transmitir esto ya que 50 GB no caben en la memoria. Sin embargo, esto plantea un problema si procesa línea por línea. ¿Qué ocurre si el texto que desea reemplazar está dividido en varias líneas?

  5. Si no tiene el problema de la línea dividida, creo que PowerShell puede manejar esto.
+1

@Keith, que realmente confía en PowerShell;) Me gustaría tal vez preocúpate por OutOfMemoryException porque 50gb es lo suficientemente grande como para recolectar pequeñas pérdidas de memoria ... solo una conjetura. Personalmente usaría 'File.Open' directamente y trabajaría con una transmisión y compararía manualmente (sin expresiones regulares). – stej

+0

¿Y no debería uno usar algún tipo de API XML para hacer esto? Solo un pensamiento. No sé si SAX o StAX están disponibles en .NET; Yo trabajo muy raramente con XML, pero hacer un reemplazo de cadena suena mal para esto. – Joey

+0

.NET tiene un lector de estilo de cursor de solo reenvío (XmlReader/XmlTextReader), un mecanismo de extracción que es un poco diferente al método de inserción de SAX. Es un poco tedioso, pero es una buena forma de hacerlo cuando todo el documento Xml no cabe en la memoria. –

-1

El carácter de escape en cadenas powershell es el backtick (`), no la barra inclinada invertida (\). Daría un ejemplo, pero el marcador invertido también es utilizado por el marcado de wiki. :(

La única cosa que usted debe tener para escapar de las comillas es -. Los períodos y tal debe ser bien sin

9

que tenía una necesidad similar (y la falta de experiencia similar PowerShell) pero improvisado una respuesta completa de las otras respuestas en esta página más un poco más de investigación.

También quería evitar el procesamiento de expresiones regulares, ya que tampoco lo necesitaba, solo un simple reemplazo de cadena, pero en un archivo grande, por lo No quería que se cargara en la memoria.

Aquí está el comando que utilicé (agregando saltos de línea para la legibilidad):

Get-Content sourcefile.txt 
    | Foreach-Object {$_.Replace('http://example.com', 'http://another.example.com')} 
    | Set-Content result.txt 

funcionó a la perfección! Nunca consumió mucha memoria (obviamente no cargó todo el archivo en la memoria), y simplemente continuó durante unos minutos y luego terminó.

+0

en un archivo de 200 MB PS tomó 3.5 GB de RAM. 30% de CPU cuando lo maté. – Tilo

+0

quizas verifique ** - ReadCount ** o ** - RAW ** http://www.happysysadm.com/2014/10/reading-large-text-files-with-powershell.html – Tilo

0

Esta es mi opinión sobre ella, sobre la base de algunas de las otras respuestas aquí:

Function ReplaceTextIn-File{ 
    Param(
    $infile, 
    $outfile, 
    $find, 
    $replace 
) 

    if(-Not $outfile) 
    { 
    $outfile = $infile 
    } 

    $temp_out_file = "$outfile.temp" 

    Get-Content $infile | Foreach-Object {$_.Replace($find, $replace)} | Set-Content $temp_out_file 

    if(Test-Path $outfile) 
    { 
    Remove-Item $outfile 
    } 

    Move-Item $temp_out_file $outfile 
} 

Y se llama así:

ReplaceTextIn-File -infile "c:\input.txt" -find 'http://example.com' -replace 'http://another.example.com'