Powershell3: различать и отображать последние n строк из файла ascii

Вопросы и ответы
Вопрос: Я думаю, это должно быть просто. Я пишу вывод журнала xcopy в текстовый файл с ежедневным ограничителем (буквально) "++++++++++++++++++++Tue 07/03/2018 0900 PM" прикрепленный к файлу журнала до каждого ежедневного резервного копирования. Таким образом, последние строки в файле обычно выглядят следующим образом: Новый день добавляет новую строку разделителя и так далее. Я хочу отобразить разделитель

Вопрос:

Я думаю, это должно быть просто. Я пишу вывод журнала xcopy в текстовый файл с ежедневным ограничителем (буквально) «++++++++++++++++++++Tue 07/03/2018 0900 PM» прикрепленный к файлу журнала до каждого ежедневного резервного копирования. Таким образом, последние строки в файле обычно выглядят следующим образом:

daily delimiter

Новый день добавляет новую строку разделителя и так далее.

Я хочу отобразить разделитель LAST и строки, которые следуют за eof.

Схема, которую я пробовал GET-Content, Select-String -Context 0,20 не работает,

PS говорит, что моя строка поиска +++++++++++++ не является регулярным выражением, не распознает путь и т.д. Любая помощь?

Память и время не под вопросом. Извините, если это слишком просто.

Лучший ответ:

msjquew полезный ответ объясняет необходимость выхода + символов. как + в регулярном выражении для этих символов. которые рассматриваются как литералы.

Таким образом, регулярное выражение соответствует строке заголовка – 20 + символов. в начале строки (^) – есть: ^+{20}

При этом, если достаточно обнаружить строки заголовка Get-Content -Delimiter 20 +, Get-Content -Delimiter – который поддерживает только литералы в качестве разделителей – предлагает простое и эффективное решение (PSv3+; предполагает входной файл some.log в текущем каталог ./):

$headerPrefix = ‘+’ * 20 # -> ‘++++++++++++++++++++’ $headerPrefix + (Get-Content ./some.log -Delimiter $headerPrefix -Tail 1)

-Delimiter использует указанную подпись строки заголовка, чтобы разбить файл на “строки” (текст между экземплярами разделителя, которые являются блоками строк здесь), а -Tail 1 возвращает последнюю “строку” (блок) путем поиска это с конца файла. Совет шляпы к mjsqu для того, чтобы помочь мне прийти к этому решению.

Следующие альтернативные решения основаны на регулярном выражении, что обеспечивает более сложное соответствие строки заголовка.

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

Мы можем использовать это в switch -regex -file для обработки всех строк файла журнала, чтобы собирать строки, которые начинаются с, и следовать последнему соответствию ^+{20}; код предполагает входной путь файла ./some.log:

# Process all lines in the log file and # collect each block lines along the way in # array $lastBlockLines, which means that after # all lines have been processed, $lastBlockLines contains # the *last* block lines. switch -regex -file ./some.log { ‘^+{20}’ { $lastBlockLines = @($_) } # start of new block, (re)initialize array default { $lastBlockLines += $_ } # add line to block } # Output the last block lines. $lastBlockLines

В качестве альтернативы, если вы готовы принять фиксированное максимальное количество строк в блоке, возможно одноконвейерное решение с использованием Select-String:

Select-String ‘^+{20}’ ./some.log -Context 0,100 | Select-Object -Last 1 | ForEach-Object { $_.Line; $_.Context.PostContext }

  • Select-String ‘^+{20}’./some.log -Context 0,100 соответствует всем строкам заголовка файла ./some.log и, благодаря -Context 0, 100, включает (до) 100 строк, которые следуйте соответствующей строке в объекте совпадения, который испускается (значение 0 означает, что строки, предшествующие соответствующей строке, должны быть включены).

  • Select-Object -Last 1 передает только последнее совпадение.

  • ForEach-Object { $_.Line; $_.Context.PostContext } ForEach-Object { $_.Line; $_.Context.PostContext } выводит последнюю строку соответствия соответствия, а также до 100 строк, которые следуют за ней.

Если вы не прочь прочитать файл дважды, вы можете комбинировать Select-String с Get-Content… | Select-Object -Skip Get-Content… | Select-Object -Skip:

Get-Content ./some.log | Select-Object -Skip ( (Select-String ‘^+{20}’ ./some.log | Select-Object -Last 1).LineNumber — 1 )

Это использует тот факт, что объекты соответствия, испускаемые Select-String имеют свойство .LineNumber отражающее номер строки, на которой было найдено данное совпадение. Передача последнего номера строки соответствия минус 1 в Get-Content… | Select-Object -Skip Get-Content… | Select-Object -Skip затем выводит соответствующую строку, а также все последующие.

Ответ №1

TL;DR; Побег + в вашем поиске, используйте “ +++” и т.д.

Фон

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

В чем смысл + в регулярном выражении?

Он сообщает двигателю, что он соответствует предыдущему оператору поиска (либо символу, диапазону, либо коду, представляющему группу символов, таких как d – цифры) один или несколько раз. Вы можете увидеть дополнительную информацию об этой ошибке в Powershell, выполнив следующее:

[regex]$x = «++++»

Возвращает:

Cannot convert value «++++» to type «System.Text.RegularExpressions.Regex». Error: «parsing «++++» — Quantifier {x,y} following nothing.» At line:1 char:1 + [regex]$x = «++++» + ~~~~~~~~~~~~~~~~~~ + CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException + FullyQualifiedErrorId : RuntimeException

Он говорит, что квантификатор (+) ничего не значит.

Поэтому нам нужно избежать использования +:

[regex]$x = «++++» $x.Match(‘++++’)

Возвращая следующее, совпадение с ошибкой:

Groups : {0} Success : True Name : 0 Captures : {0} Index : 0 Length : 4 Value : ++++

улучшение

Если вы знаете, сколько + есть, вы можете сопоставить «+{20}», если их осталось 20. Или из предыдущего примера:

[regex]$x = «+{4}» $x.Match(‘++++’) Ответ №2

Другой способ использования RegEx – разделить файл на разделы.

  • используйте Get-Content с параметром -Raw чтобы иметь одну строку, а не массив строк
  • используйте непрозрачный положительный результат, чтобы разделить файл на разделы, начиная с
    20 * + -split ‘(?=+{20})’, которые не пусты -ne »
  • используйте индекс [-1] чтобы получить последний раздел.

Образец вывода

PS> ((Get-Content ‘.LogFile.txt’ -raw) -split ‘(?=+{20})’ -ne »)[-1] ++++++++++++++++++++Mon 07/03/2018 0900 PM 0 Files(s) copied Xcopy SUCCEEDED K: to J:MyUSBBackups Mon 07/02/2018 0900 PM 0 Files(s) copied Xcopy SUCCEEDED K: to J:MyUSBBackupsOutlookBak Mon 07/02/2018 0900 PM Ответ №3

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

Однако, исходя из того, что вы опубликовали. Вот один из способов сделать это, я уверен, что есть более элегантные способы, но это q & d (быстрый и грязный). Также, как военный ветеринар (20+ лет) и все еще живет и работает в военное время, 0900 9:00, где 2100 – 21:00. 8 ^}… Просто говорю…

# Get the lines in the file ($DataSet = Get-Content -Path ‘.LogFile.txt’) # Results ++++++++++++++++++++Mon 07/02/2018 0900 PM 0 Files(s) copied Xcopy SUCCEEDED K: to J:MyUSBBackups Mon 07/02/2018 0900 PM 0 Files(s) copied Xcopy SUCCEEDED K: to J:MyUSBBackupsOutlookBak Mon 07/02/2018 0900 PM ++++++++++++++++++++Mon 07/03/2018 0900 PM 0 Files(s) copied Xcopy SUCCEEDED K: to J:MyUSBBackups Mon 07/02/2018 0900 PM 0 Files(s) copied Xcopy SUCCEEDED K: to J:MyUSBBackupsOutlookBak Mon 07/02/2018 0900 PM # Get the index of the LastDateEntry, using a string match (RegEx) ($LastDateEntry = (Get-Content -Path ‘.LogFile.txt’ | %{$_ | Select-String -Pattern ‘[+].*’}) | Select -Last 1) # Results ++++++++++++++++++++Mon 07/03/2018 0900 PM # Get the LastDateEntryIndex ($DateIndex = (Get-Content -Path ‘.LogFile.txt’).IndexOf($LastDateEntry)) # Results 5 # Get the data using the index ForEach($Line in $DataSet) { If ($Line.ReadCount -ge $DateIndex) { Get-Content -Path ‘.LogFile.txt’ | Select-Object -Index ($Line.ReadCount) } } # Results ++++++++++++++++++++Mon 07/03/2018 0900 PM 0 Files(s) copied Xcopy SUCCEEDED K: to J:MyUSBBackups Mon 07/02/2018 0900 PM 0 Files(s) copied Xcopy SUCCEEDED K: to J:MyUSBBackupsOutlookBak Mon 07/02/2018 0900 PM

Оцените статью
Добавить комментарий