Получите регулярные выражения PowerShell в таблицу - PullRequest
4 голосов
/ 12 декабря 2011

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

2011-12-09 18:20:55, ABC.EXE[3b78], The rest of the line...

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

Что у меня есть (разделить на другую строку для удобства чтения)

gci -filter *.log -r 
 | select-string '(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}), ABC.EXE\[(.{4})' 
 | % { $_.matches } | % { $_.groups } | % { $_.value }

выплевывает захваченные. Я хотел бы проигнорировать первый захват и объединить второй и третий в одной строке.

Помощь? Пожалуйста?

Редактировать: DOH! Не могу ответить на свой вопрос. Итак ...

Хорошо, я думаю, что я на правильном пути. ТАК вопрос здесь помог мне получить отдельные детали, которые я хотел, а именно:

$_.matches[0].groups[1].value, $_.matches[0].groups[2].value

Затем в статье MSDN здесь показано, как «объединить» биты в объект, что позволяет группировать / сортировать / манипулировать им. Конечный результат

gci -filter *.log | select-string '(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}), ABC.EXE\[(.{4})' 
 | % { new-object object 
  | add-member NoteProperty Name $_.matches[0].groups[1].value -passthru 
  | add-member NoteProperty PId $_.matches[0].groups[2].value -passthru }

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

1 Ответ

4 голосов
/ 12 декабря 2011

Вы можете создавать новые объекты проще в PowerShell v2, где командлет New-Object поддерживает параметр -Property, который получает хеш-таблицу свойств:

New-Object PSObject -Property @{
    Name = $_.matches[0].groups[1].value
    PId = $_.matches[0].groups[2].value
}

Вообще, я бы сделал обработку немного по-другому, хотя:

# prepare table
$data = $(switch -Regex -File filename {
    '^[^,]+' { $date = [datetime]$Matches[0] }
    '(?<=\[)[^\]]+' { $id = $Matches[0] }
    '$' { New-Object PSObject -Property @{
        Date = $date
        PId = $id
    } }
})

Использование switch -regex стало хорошим способом (по крайней мере для меня) для создания быстрых и грязных парсеров для текстовых данных. С -Regex будут запущены все совпадающие случаи, в данном случае все (так что это просто удобство для разделения различных частей сопоставления). Первый захватывает дату и время и сохраняет их в переменной (даже в виде значения DateTime); вторая получает идентификатор процесса, а третья, совпадающая с концом строки, собирает все вместе.

Просто личное предпочтение, хотя; Я на самом деле никогда не использовал Select-String.

$data |
    group PId |
    foreach { New-Object PSObject -Property @{
        PId = $_.Name
        MinDate = @($_.Group | sort Date)[0].Date
    } }

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

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

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