2010-05-06 15 views
5

Chcę znaleźć fragment tekstu w dużym pliku XML i chcę go zastąpić innym tekstem. Rozmiar pliku wynosi około (50 GB). Chcę to zrobić w wierszu poleceń. Patrzę na Powershell i chcę wiedzieć, czy poradzi sobie z dużymi rozmiarami. Chciałbym również znać składnię, by uniknąć kluczowych operatorów w grze powershell. Jestem nowicjuszem PowerShellZnajdź i zamień w dużym pliku

Obecnie próbuję coś takiego, ale nie podoba

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

Tekst chcę zastąpić to xmlns: xsi = "http: //www.w3. org/2001/XMLSchema-instance " z pustym ciągiem" ".

Pytania

  1. Can PowerShell obsługiwać duże plików
  2. Jak wywołać skrypt powershell z wiersza poleceń
  3. składni ucieczki kluczowych operatorów w PowerShell, a następnie listę kluczowych operatorów w powerShell.
  4. Nie chcę, aby zastąpić się w pamięci i wolę przesyłanie strumieniowe przy założeniu, , które nie przyniosą serwerowi na kolanach.
  5. Czy są jakieś inne sposoby mogę wziąć (inny tools/strategię?)

Dzięki

Odpowiedz

3

to nie podoba, ponieważ nie można odczytać z pliku i zapis z powrotem do niego w w tym samym czasie używając Get-Content/Set-Content. Zalecam użycie pliku tymczasowego, a następnie na końcu zmień nazwę pliku1.xml na plik1.xml.bak i zmień nazwę pliku tymczasowego na file1.xml.

  1. Tak długo, jak nie próbujesz załadować całego pliku naraz. Linia po linii będzie działać, ale będzie nieco powolna. Użyj parametru -ReadCount i ustaw go na 1000, aby zwiększyć wydajność.
  2. Która linia poleceń? PowerShell? Jeśli tak, to możesz wywołać skrypt tak, jak .\myscript.ps1 i jeśli ma on parametry, to c:\users\joe\myscript.ps1 c:\temp\file1.xml.
  3. Ogólnie rzecz biorąc dla wyrażeń regularnych używam pojedynczych cudzysłowów, jeśli nie ma potrzeby odwoływania się do zmiennych PowerShell. Wtedy musisz się tylko martwić o ucieczkę regex, a nie także ucieczkę PowerShell. Jeśli chcesz użyć podwójnych cudzysłowów, wówczas znak "od tyłu" to znak "escape char" w podwójnych cudzysłowach, np. "` $ p1 jest ustawione na $ ps1 ". W przykładzie pojedynczy cytując upraszcza regex (Uwaga: ukośniki nie są metaznakami w regex):

    'xmlns: xsi = ""'

    http://www.w3.org/2001/XMLSchema-instance
  4. Absolutnie chcesz przesyłać strumieniowo, ponieważ 50 GB nie pasuje do pamięci. Jednakże stanowi to problem w przypadku przetwarzania linii po linii. Co się stanie, jeśli tekst, który chcesz zastąpić, zostanie podzielony na wiele linii?

  5. Jeśli nie masz problemu z dzieloną linią, myślę, że PowerShell sobie z tym poradzi.
+1

@Keith, naprawdę można ufać PowerShell;) Chciałbym być może martw się o wyjątek OutOfMemoryException, ponieważ 50 gb jest wystarczająco duże, aby zebrać małe wycieki pamięci. Tylko zgadnij. Osobiście użyłbym bezpośrednio 'File.Open' i pracowałem ze strumieniem i porównywałem ręcznie (bez regex). – stej

+0

A do tego nie powinno się używać jakiegoś interfejsu API XML? Tylko myśl. Dunno, jeśli SAX lub StAX są dostępne w .NET; Pracuję zbyt rzadko z XML, ale ciąg znaków zastępuje dźwięki niewłaściwe. – Joey

+0

. NET ma przedni czytnik stylu kursora (XmlReader/XmlTextReader) - mechanizm ściągania, który jest nieco inny niż podejście push SAX. To trochę żmudne, ale dobrym sposobem, aby przejść, gdy cały dokument Xml nie mieści się w pamięci. –

-1

Znakiem kontrolnym w łańcuchach PowerLink jest backtick (`), a nie ukośnik odwrotny (\). Podam przykład, ale zwrot jest również używany przez znaczniki wiki. :(

Jedyną rzeczą, którą należy mieć na ucieczkę jest cytaty -. Okresy i takie powinny być w porządku bez

9

miałem podobną potrzebę (i podobnych brak doświadczenia PowerShell), ale sklecony kompletna odpowiedź z innych odpowiedzi na tej stronie plus trochę więcej badań

Chciałem także uniknąć przetwarzania wyrażenia regularnego, ponieważ też go nie potrzebowałem - wystarczy zwykła zamiana ciągu - ale na dużym pliku, więc Nie chciałem, aby zostało wczytane do pamięci.

Oto polecenie, którego użyłem (dodanie linii łamania dla czytelności):

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

Pracuje idealnie! Nigdy nie wysysałem dużo pamięci (oczywiście nie włożyłem całego pliku do pamięci) i po prostu chugowałem przez kilka minut, a potem skończyłem.

+0

na pliku 200 MB PS zajął 3,5 GB pamięci RAM. 30% CPU, gdy go zabiłem. – Tilo

+0

może sprawdzić ** - ReadCount ** lub ** - RAW ** http://www.happysysadm.com/2014/10/reading-large-text-files-with-powershell.html – Tilo

0

To jest moje zdanie na ten temat, opierając się na niektórych innych odpowiedzi tutaj:

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 
} 

i nazwał tak:

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