2010-05-06 14 views
5

Voglio trovare una parte di testo in un file xml di grandi dimensioni e voglio sostituirlo con un altro testo. La dimensione del file è intorno a 50 GB. Voglio farlo in linea di comando. Sto guardando PowerShell e voglio sapere se può gestire le grandi dimensioni. Inoltre vorrei conoscere la sintassi per l'escape degli operatori chiave in PowerShell. Sono un novizio PowerShellTrova e sostituisci in un file di grandi dimensioni

Attualmente sto cercando qualcosa di simile, ma non piace

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

Il testo voglio sostituire è xmlns: xsi = "http: //www.w3. org/2001/XMLSchema-instance " con stringa vuota" ".

Domande

  1. Can PowerShell gestire grandi file
  2. Come chiamare lo script PowerShell da linea di comando
  3. La sintassi per sfuggire chiave operatori in PowerShell e l'elenco degli operatori chiave in PowerShell.
  4. Non voglio che la sostituzione avvenga nella memoria e preferisco lo streaming assumendo che non porterà il server a le sue ginocchia.
  5. Ci sono altri approcci che posso prendere (Diverso strumenti/strategia?)

Grazie

risposta

3

Non piace perché non è possibile leggere da un file e scrivere di nuovo esso in allo stesso tempo usando Get-Content/Set-Content. Consiglio di utilizzare un file temporaneo e alla fine rinominare file1.xml in file1.xml.bak e rinominare il file temp in file1.xml.

  1. Sì, finché non si tenta di caricare l'intero file in una volta. Il line-by-line funzionerà ma sarà un po 'lento. Utilizzare il parametro -ReadCount e impostarlo su 1000 per migliorare le prestazioni.
  2. Quale riga di comando? PowerShell? Se è così allora puoi invocare il tuo script come .\myscript.ps1 e se prende i parametri allora c:\users\joe\myscript.ps1 c:\temp\file1.xml.
  3. In generale per le espressioni regolari, utilizzare le virgolette singole se non è necessario fare riferimento alle variabili di PowerShell. Quindi devi solo preoccuparti dell'espressione di regex e non dell'esecuzione forzata di PowerShell. Se hai bisogno di usare virgolette, il carattere back-tick è il carattere di escape tra virgolette, ad es. "` $ p1 è impostato su $ ps1 ". Nel tuo esempio la citazione semplice semplifica la tua espressione regolare (nota: le barre in avanti non sono metacaratteri nella regex):

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

  4. Assolutamente si desidera eseguire lo streaming poiché 50 GB non si adatta alla memoria. Tuttavia, ciò pone un problema se si elabora linea per linea. Cosa succede se il testo che si desidera sostituire è diviso su più righe?

  5. Se non si dispone del problema della linea di divisione, penso che PowerShell sia in grado di gestirlo.
+1

@Keith, si ha realmente fidarsi PowerShell;) lo farei forse preoccuparsi di OutOfMemoryException perché 50gb è abbastanza grande da raccogliere piccole perdite di memoria .. solo un'ipotesi. Personalmente userò direttamente 'File.Open' e lavorerò con un flusso e confronteremo manualmente (nessuna regex). – stej

+0

E non si dovrebbe usare una sorta di API XML per fare questo? Solo un pensiero. Non so se SAX o StAX sono disponibili in .NET; Lavoro troppo raramente con XML, ma fare una stringa sostituisce i suoni sbagliati per questo. – Joey

+0

.NET ha un forward-only, lettore di stili di cursore (XmlReader/XmlTextReader) - un meccanismo di pull che è leggermente diverso dall'approccio push SAX. È un po 'noioso, ma un buon modo per andare quando l'intero documento Xml non si adatta alla memoria. –

-1

Il carattere di escape nelle stringhe di PowerShell è l'apice (`), non il backslash (\). Darei un esempio, ma il backtick è anche usato dal markup wiki. :(

L'unica cosa che si dovrebbe avere per sfuggire è le virgolette -. Periodi e come dovrebbe andare bene senza

9

ho avuto una simile esigenza (e simile mancanza di esperienza PowerShell), ma messo insieme una risposta completa dalle altre risposte in questa pagina più un po 'di ricerca

Volevo anche evitare l'elaborazione delle espressioni regolari, poiché non ne avevo nemmeno bisogno - basta una semplice stringa di sostituzione - ma su un file di grandi dimensioni, quindi Non volevo che fosse caricato in memoria

Ecco il comando che ho usato (aggiungendo interruzioni di riga per la leggibilità):

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

Ha funzionato perfettamente! Non ho mai risucchiato molta memoria (molto ovviamente non ha caricato l'intero file in memoria), e ho solo fatto un salto per alcuni minuti e poi finito.

+0

su un file da 200 MB PS ha preso 3,5 GB di RAM. CPU del 30% quando l'ho ucciso. – Tilo

+0

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

0

Questo è il mio prendere su di esso, sulla base alcune delle altre risposte qui:

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 
} 

E chiamato in questo modo:

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