2010-05-06 4 views
5

Я хочу найти фрагмент текста в большом XML-файле и заменить его другим текстом. Размер файла составляет около 50 ГБ. Я хочу сделать это в командной строке. Я смотрю на Powershell и хочу знать, может ли он справиться с большими размерами. Также я хотел бы знать синтаксис для экранирования ключевых операторов в powershell. Я новичок PowerShellНайти и заменить в большом файле

В настоящее время я пытаюсь что-то вроде этого, но это не нравится

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

текст Я хочу, чтобы заменить это XMLNS: XSI = "HTTP: //www.w3. org/2001/XMLSchema-instance " с пустой строкой" ".

Вопросы

  1. Может Powershell обрабатывать большие файлы
  2. Как вызвать скрипт Powershell из командной строки
  3. Синтаксис для выхода ключевых операторов в Powershell и список ключевых операторов в powerShell.
  4. Я не хочу, чтобы замена происходила в памяти и предпочла потоковое использование в предположении , что не приведет сервер к его коленям.
  5. Существуют ли какие-либо другие подходы, я могу взять (Different инструменты/стратегии?)

Благодаря

ответ

3

Это не нравится это, потому что вы не можете прочитать из файла и записать обратно к нему в в то же время используя Get-Content/Set-Content. Я рекомендую использовать временный файл, а затем в конце, переименуйте file1.xml в файл1.xml.bak и переименуйте файл temp в файл file1.xml.

  1. Да, если вы не пытаетесь загрузить весь файл сразу. Line-by-line будет работать, но будет немного медленнее. Используйте параметр -ReadCount и установите его на 1000 для повышения производительности.
  2. Какая командная строка? PowerShell? Если это так, вы можете вызвать свой скрипт так: .\myscript.ps1 и если он принимает параметры, то c:\users\joe\myscript.ps1 c:\temp\file1.xml.
  3. В общем случае для регулярных выражений я бы использовал одинарные кавычки, если вам не нужно ссылаться на переменные PowerShell. Тогда вам нужно только беспокоиться об экранировании регулярных выражений, а не об исключении PowerShell. Если вам нужно использовать двойные кавычки, то символ обратного тика является escape-символом в двойных кавычках, например. msgstr "$ p1 установлен в $ ps1". В вашем примере одного процитировать упрощает регулярное выражение (примечание: прямые слэши не метасимволы в регулярном выражении):

    «XMLNS: XSI =„http://www.w3.org/2001/XMLSchema-instance“»

  4. Абсолютно вы хотите потокового потока, так как 50 ГБ не поместится в памяти. Однако это создает проблему, если вы обрабатываете строки за строкой. Что делать, если текст, который вы хотите заменить, разделен на несколько строк?

  5. Если у вас нет проблемы с разделенной линией, я думаю, PowerShell может справиться с этим.
+1

@Keith, вы действительно доверяете PowerShell;) Я бы, возможно, беспокоиться об OutOfMemoryException, потому что 50 гб достаточно велик, чтобы собирать небольшие утечки памяти .. просто догадка. Лично я бы использовал непосредственно 'File.Open' и работал с потоком и сравнивал вручную (без регулярного выражения). – stej

+0

И не нужно ли использовать какой-либо XML API для этого? Просто мысль. Dunno, если SAX или StAX доступны в .NET; Я слишком редко работаю с XML, но для этого замена строки звучит неправильно. – Joey

+0

.NET имеет встроенный читатель с курсором (XmlReader/XmlTextReader) - механизм вытягивания, который немного отличается от подхода SAX push. Это немного утомительно, но хороший способ пойти, когда весь документ Xml не поместится в памяти. –

-1

Символ-побег в строках powershell - это обратная сторона (`), а не обратная косая черта (\). Я приведу пример, но обратная сторона также используется разметкой wiki. :(

Единственное, что вы должны бежать в кавычки -. Периоды и такие должны быть хорошо без

9

У меня была подобная необходимость (и подобное отсутствие опыта Powershell) но слепленный полный ответ от других ответов на этой странице плюс немного больше исследований.

Я также хотел избежать обработки регулярных выражений, так как мне это тоже не понадобилось - просто заменить строку - но на большой файл, так что Я не хотел, чтобы он загружался в память.

Вот эта команда, которую я использовал (добавление строк для чтения):

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

Работало отлично! Никогда не засасывал много памяти (это, очевидно, не загрузило весь файл в память), и просто проглотил несколько минут, затем закончил.

+0

на 200 МБ файла PS занял 3.5 ГБ оперативной памяти. 30% CPU, когда я его убил. – Tilo

+0

возможно, проверьте ** - ReadCount ** или ** - RAW ** http://www.happysysadm.com/2014/10/reading-large-text-files-with-powershell.html – Tilo

0

Это мой взгляд на него, опираясь на некоторые другие ответы здесь:

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 
} 

И называется так:

ReplaceTextIn-File -infile "c:\input.txt" -find 'http://example.com' -replace 'http://another.example.com' 
Смежные вопросы