首页 > 解决方案 > 如何使用 Powershell 将哈希表与另一个哈希表进行比较?

问题描述

我开始使用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])
    }
}

现在如何比较这两个哈希图?

标签: powershellhashmaphashtable

解决方案


JPBlanc建议在对该问题的评论中对记录进行分组,Group-Objectcmdlet确实提供了一个概念上优雅的解决方案:

注意:假设一个给定的关键字只有一个条目,它始终是起始条目。

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}

这可能不是您想要的格式,但鉴于输出是objects,这在 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 hours, 3 minutes, ...) 是一个[TimeSpan]实例的字符串表示,它是减去两个时间点 ( [datetime]instances) 的结果。


推荐阅读