Как я могу сравнить хеш-таблицу с другой с помощью Powershell? - PullRequest
0 голосов
/ 28 августа 2018

Я начинаю с PowerShell, и мои знания сейчас очень плохие. У меня есть этот файл .log, который выглядит следующим образом:

18.7.2017 12:59:15  Starting thread: KEYWORD1
18.7.2017 12:59:33  Thread finished; ... KEYWORD1
18.7.2017 13:32:19  Starting thread: KEYWORD2
18.7.2017 13:34:8  Thread finished;... KEYWORD2

Я хочу выяснить, завершен ли каждый начатый поток. Если есть незаконченный поток, я хочу сравнить метку времени с текущим временем.

Я думал, что хеш-таблица поможет, и вот что я придумал:

foreach($line in Get-Content $sourceDirectory)
{
    if($line -like "*Starting thread*")
    {
        $arrStart = $line -split ' '
        $startThreads=$arrStart[$arrStart.Length-1]
        $hashmap1 = @{$arrEnd[$arrEnd.Length-1] = $arrEnd[1]}
    }

    if($line -like "*Thread finished*")
    {
        $arrEnd = $line -split ' '
        $hashmap2 = @{$arrEnd[$arrEnd.Length-1] = $arrEnd[1]}
        $endThreads=($arrEnd[1]+" "+$arrEnd[$arrEnd.Length-1])
    }
}

Как теперь можно сравнить эти два хеш-карты?

Ответы [ 3 ]

0 голосов
/ 28 августа 2018

Один из способов сделать это - использовать RegEx, чтобы отделить каждую строку, а затем создать новый объект из деталей. Например:

Get-Content .\data.txt |
    ForEach-Object {
        if ($_ -match "^(?<time>(\d+\.){2}\d+ (\d{2}:){2}\d{2}).*(?<state>Starting|finished).*\b(?<keyword>\w+)$")
        {
            [PsCustomObject]@{
                Keyword = $matches.keyword
                Action = $(if($matches.state -eq "Starting"){"Start"}else{"Finish"})
                Time = (Get-Date $matches.time)
            }
        }
    }

Предположим, у вас есть файл журнала (data.txt) со следующим содержимым:

18.7.2017 12:59:15  Starting thread: KEYWORD1
18.7.2017 13:32:19  Starting thread: KEYWORD2
18.7.2017 12:59:15  Starting thread: KEYWORD3
18.7.2017 13:34:18  Thread finished;... KEYWORD2
18.7.2017 12:59:15  Starting thread: KEYWORD4
18.7.2017 13:34:18  Thread finished;... KEYWORD3
18.7.2017 12:59:15  Starting thread: KEYWORD5
18.7.2017 13:34:18  Thread finished;... KEYWORD5

Запустив приведенный выше код, выдает:

Keyword  Action Time               
-------  ------ ----               
KEYWORD1 Start  18/07/2017 12:59:15
KEYWORD2 Start  18/07/2017 13:32:19
KEYWORD3 Start  18/07/2017 12:59:15
KEYWORD2 Finish 18/07/2017 13:34:18
KEYWORD4 Start  18/07/2017 12:59:15
KEYWORD3 Finish 18/07/2017 13:34:18
KEYWORD5 Start  18/07/2017 12:59:15
KEYWORD5 Finish 18/07/2017 13:34:18

Это не так уж и много лучше по сравнению с необработанным файлом, но теперь, когда у вас есть некоторые объекты, вы можете легче их обрабатывать. Например, вы можете увидеть, какие из них не имеют соответствующего начала / конца, добавив следующее после последней скобки:

| Group-Object Keyword -NoElement | Sort-Object Count -Descending

Это дает следующий вывод:

Count Name                     
----- ----                     
    2 KEYWORD2                 
    2 KEYWORD3                 
    2 KEYWORD5                 
    1 KEYWORD1                 
    1 KEYWORD4  

Теперь легче увидеть, у кого из них есть пара старт / финиш (например, в каждой группе по 2 предмета)

Вероятно, это немного излишне для вашего сценария, но, как вы сказали, вы были новичком в PowerShell, я подумал, что упомяну об этом, поскольку часто очень полезно превращать текст в подобный объект для обработки.

0 голосов
/ 28 августа 2018

JPBlanc рекомендует группировать записей в комментарии к вопросу, а командлет Group-Object действительно предлагает концептуально элегантное решение:

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

Select-String 'Starting thread:|Thread finished;' file.log | 
  Group-Object { (-split $_)[-1] } | Where-Object { $_.Count % 2 -eq 1 }
  • Вызов Select-String извлекает только интересующие строки (начало потока, окончание потока), используя регулярное выражение (регулярное выражение)

  • Вызов Group-Object группирует результирующие строки по последнему ([-1]) токену, разделенному пробелами (-split ...) в каждой строке ($_), т. Е. По ключевым словам.

  • Where-Object затем возвращает только те результаты, которые имеют нечетное количество записей, т. Е. Те, которые не спарены , представляющие начало, но не нити.

Это дает что-то вроде следующего:

Count Name          Group
----- ----          -----
    1 KEYWORD3      {/Users/jdoe/file.log:5:28.8.2018 08:59:16  Starting thread: KEYWORD3}

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

Технически, вышеприведенная команда выводит [Microsoft.PowerShell.Commands.GroupInfo] экземпляров, чье свойство .Group в этом случае содержит [Microsoft.PowerShell.Commands.MatchInfo] экземпляров, как вывод Select-String.


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

$now = Get-Date
Select-String 'Starting thread:|Thread finished;' file.log  | 
  Group-Object { (-split $_)[-1] } | Where-Object { $_.Count % 2 -eq 1 } | ForEach-Object {
    foreach ($matchInfo in $_.Group) { # loop over started-only lines
      $tokens = -split $matchInfo.Line # split into tokens by whitespace
      $date, $time = $tokens[0..1]     # extract date and time (first 2 tokens)
      $keyword = $tokens[-1]           # extract keyword (last token)
      # Parse date+time into a [datetime] instance.
      # Note: Depending on the current culture, [datetime]::Parse("$date $time") may do.
      $start = [datetime]::ParseExact("$date $time", 'd\.M\.yyyy HH:mm:ss', [cultureinfo]::InvariantCulture)
      # Custom output string containing how long ago the thread was started:
      "Thread $keyword hasn't finished yet; time elapsed since it started: " +
        ($now - $start).ToString('g')
    }
  }

Это дает что-то вроде следующего:

Thread KEYWORD3 hasn't finished yet; time elapsed since it started: 2:03:35.347563

2:03:35.347563 (2 часа, 3 минуты, ...) - строковое представление экземпляра [TimeSpan], являющегося результатом вычитания двух точек во времени ([datetime] экземпляров).

0 голосов
/ 28 августа 2018

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

# Find Lines with `Starting thread` and drop everything before the final space to get the array of KEYWORDS that started
$Start = (Select-String $sourceDirectory 'Starting thread') -replace '^.*Starting thread.*\s+'
# Find Lines with `Thread finished` and drop everything before the final space to get the array of KEYWORDS that finished
$Finish = (Select-String $sourceDirectory 'Thread finished') -replace '^.*Thread finished.*\s+'
# Find everything that started but hasn't finished.
$Start.where({$_ -notin $Finish})

Примечания: Требуется PS4 + для where метода и -notin. Также было сделано предположение, что поток не запускается и останавливается несколько раз.

...