Powershell импортирует данные из текстового файла после строки

Кажется, в Интернете есть похожие вопросы, хотя ответы на них различаются, и я просто не могу получить результат, который ищу.

Ниже просто добавляется содержимое текстового файла в конец файла.

Add-Content -Path "HeartBeat.txt" -Value (Get-Content "insertme.txt")

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

Искусственный пример текстового файла, ищущего строку «HeartBeat».

<xml>
<Server>
  <HeartBeat>1</HeartBeat>
</Server>

Существует еще один текстовый файл с именем «insertme.txt», который будет вставлять свое содержимое в новую строку после «HeartBeat».

<dummydata>
<port></port>
<ipaddress></ipaddress>

После добавления будет

<xml>
<Server>
  <HeartBeat>1</HeartBeat>
  <dummydata>
  <port></port>
  <ipaddress></ipaddress>
</Server>

Любая помощь будет оценена по достоинству.

Спасибо


person PX IT    schedule 31.07.2018    source источник
comment
Предполагая, что тестовый файл, в котором у вас есть строка HeartBeat, имеет имя HeartBeat.txt, и вы хотите добавить содержимое Insertme.txt в HeartBeat.txt, вы можете использовать следующий код: Get-Content Insertme.txt | Out-File HeartBeat.txt -Append   -  person SavindraSingh    schedule 31.07.2018
comment
@SavindraSingh: Этот вопрос касается не добавления содержимого, а вставки его после строки, содержащей определенную строку.   -  person mklement0    schedule 31.07.2018


Ответы (1)


Если вам нужно действительно надежное решение, используйте обработку XML, которую PowerShell поддерживает через [xml](System.Xml.XmlDocument) типа .NET.

Если вам все еще нужно чисто текстовое решение, попробуйте следующее (PSv3+; полностью считывает оба файла в память; я использую в коде символ новой строки только для LF ("`n"); замените его на "`r`n", если вы хотите, чтобы символы новой строки CRLF ):

(Get-Content -Raw Heartbeat.txt) -replace
  '(?m)^.*<HeartBeat>.*$',
  ('$&' + "`n" + (Get-Content -Raw InsertMe.txt).TrimEnd() -replace '(?m)^', '  '))|
    Set-Content HeartBeat.txt # PSv5+: Add -NoNewline to avoid extra newline

Примечание. Единственная причина, по которой можно читать из Heartbeat.txt и записывать в него в одном конвейере, заключается в том, что его содержимое считывается в память вверх. полностью, из-за (...) вокруг команды Get-Content.
Хотя этот подход удобен, он также несет в себе небольшой риск потери данных, который может произойти, если конвейер будет прерван до того, как все содержимое будет записано обратно в файл.

  • Get-Content -Raw считывает файл в память полностью, как одну строку.

  • Регулярное выражение '(?m)^.*<HeartBeat>.*$' соответствует одной строке, содержащей подстроку <HeartBeat> (обратите внимание, что оператор -replace обычно ищет несколько совпадений)

  • Выражение замены '$&' + "`n" + (Get-Content -Raw InsertMe.txt).TrimEnd() заменяет совпадающую строку самой собой ($&), за которой следует перевод строки и содержимое файла InsertMe.txt.

    • .TrimEnd() is used to remove trailing newlines (and whitespace in general) so that insertion does not vary based on whether the file happens to end in a newline or not.
  • Если вы хотите избежать дополнительной новой строки в конце обновленного файла,
    используйте Set-Content -NoNewline, но учтите, что для этого требуется PSv5+.
    В более ранних версиях вы могли применять .TrimEnd() ко всему выражению перед его отправкой в ​​Set-Content.


Если вы хотите изменить вставку, чтобы применить фиксированный отступ к каждой строке вставленного содержимого:

(Get-Content -Raw Heartbeat.txt) -replace
  '(?m)^.*<HeartBeat>.*$',
  ('$&' + "`n" + (Get-Content -Raw InsertMe.txt).TrimEnd() -replace '(?m)^', '  '))|
    Set-Content HeartBeat.txt # PSv5+: Add -NoNewline to avoid extra newline
person mklement0    schedule 31.07.2018