Найти и заменить в большом файле - PullRequest
6 голосов
/ 06 мая 2010

Я хочу найти фрагмент текста в большом 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. Есть ли другие подходы, которые я могу использовать инструменты / стратегия?)

Спасибо

Ответы [ 4 ]

11 голосов
/ 02 июня 2011

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

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

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

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

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

4 голосов
/ 07 мая 2010

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

  1. Да, если вы не пытаетесь загрузить весь файл сразу. Линия за строкой будет работать, но будет немного медленной. Используйте параметр -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 справится с этим.
0 голосов
/ 19 сентября 2017

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

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' 
0 голосов
/ 07 мая 2010

Экранирующим символом в строках powershell является обратная косая черта (`), а не обратная косая черта (\). Я бы привел пример, но знак обратной черты также используется вики-разметкой. (

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...