【问题标题】:Parsing the log file using select-String使用 select-String 解析日志文件
【发布时间】:2018-11-11 20:29:33
【问题描述】:

团队, 在此先感谢,我是一名 ITPro 并正在学习 PowerShell。我有一个日志文件,其中包含以下格式的数据。我附上了图片。 我正在查找所有已完成传输的行,然后运行 ​​foreach 循环以使用 -eq 运算符查找日期与当前日期匹配的行

然后我想从运行 foreach 循环的当前行获取特定文件名。我的示例中的示例:日志中第一个完成的传输行与当前日期匹配,因此我想获取文件名 HardwareEvents.evtx。

但我找不到任何方法可以帮助我在当前运行的每一行中解析文件名。

如果我得到文件名,我可以使用 powersell cmdlet 删除文件。

        $var = Select-String -Path "C:\Creds\AzCopyVerbose.log" -Pattern 'Finished Transfer' | `
Select-Object -Last 20 | ForEach-Object `
    {
      if (($_.Line).Substring(1,10) -eq (Get-Date).ToString('yyyy/MM/dd'))
      {
        $_.Line. // There is no method which I'm aware of need help in this if statement
      }
      Else {Write-Host "The date present in the azcopy verbose log is older"}
    }

【问题讨论】:

  • 请将要搜索的数据以文本而非图片的形式发布。我认为单个正则表达式可能带有环视功能,可以使用捕获组过滤相关文件名。

标签: powershell


【解决方案1】:

要从今天日期所在的日志中获取文件名,您可以使用以下命令:

$logfile = 'C:\Creds\AzCopyVerbose.log'
$today = Get-Date -UFormat "%Y/%m/%d"
$pattern = '^\[(?<date>\d{4}/\d{2}/\d{2}).*Finished transfer:\s+(?<filename>.*)\s+=>.*$'
Select-String -Path $logfile -Pattern $pattern | Select-Object -Last 20 | ForEach-Object {
    $null = $_.Line -match $pattern
    if ($matches['date'] -eq $today) {
        Write-Host $matches['filename']
    }
    else {
        Write-Host "The date present in the azcopy verbose log is older"
    }
}

除了使用Select-String,你也可以这样做,它只需要匹配一次模式,所以在我看来更简洁:

$logfile = 'C:\Creds\AzCopyVerbose.log'
$today = Get-Date -UFormat "%Y/%m/%d"
$pattern = '^\[(?<date>\d{4}/\d{2}/\d{2}).*Finished transfer:\s+(?<filename>.*)\s+=>.*$'
Get-Content -Path $logfile | Select-Object -Last 20 | Where-Object { $_ -match $pattern } | ForEach-Object {
    if ($matches['date'] -eq $today) {
        Write-Host $matches['filename']
    }
    else {
        Write-Host "The date present in the azcopy verbose log is older"
    }
}

附言我使用Get-Date -UFormat "%Y/%m/%d",因为(Get-Date).ToString('yyyy/MM/dd') 在我的荷兰机器上输出2018-11-10

正则表达式详细信息

^                     Assert position at the beginning of the string
\[                    Match the character “[” literally
(?<date>              Match the regular expression below and capture its match into backreference with name “date”
   \d                 Match a single digit 0..9
      {4}             Exactly 4 times
   \/                 Match the character “/” literally
   \d                 Match a single digit 0..9
      {2}             Exactly 2 times
   \/                 Match the character “/” literally
   \d                 Match a single digit 0..9
      {2}             Exactly 2 times
)
.                     Match any single character that is not a line break character
   *                  Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
Finished\ transfer:   Match the characters “Finished transfer:” literally
\s                    Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
   +                  Between one and unlimited times, as many times as possible, giving back as needed (greedy)
(?<filename>          Match the regular expression below and capture its match into backreference with name “filename”
   .                  Match any single character that is not a line break character
      *               Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
)
\s                    Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
   +                  Between one and unlimited times, as many times as possible, giving back as needed (greedy)
=>                    Match the characters “=>” literally
.                     Match any single character that is not a line break character
   *                  Between zero and unlimited times, as many times as possible, giving back as needed (greedy)
$                     Assert position at the end of the string (or before the line break at the end of the string, if any)

【讨论】:

  • 首先,感谢 Theo 教我实现这一目标的新方法,我今天学到了新东西。再次感谢。我只想知道一件事,您是如何创建正则表达式模式的?你能指导我通过一个链接或你创建这个的方式吗?这会很有帮助。再次感谢。
  • @aquib.rocks 我已经添加了正则表达式的详细信息。我总是使用 RegexBuddy(不是免费的..),但您也可以在 regex101.com 上进行实验
  • 你真是太棒了我的朋友,当你没有编写任何代码时,我对正则表达式如何知道文件名感到困惑。但是现在我通过您的解释知道它会自动知道 => 之前的任何内容都是通过正则表达式的文件名。 (?.*)\s+=>.*$' 感谢兄弟的所有帮助。
  • 很好,但即使使用Select-String,您也不必匹配两次,因为您可以通过$_.Matches[0].Groups 访问捕获组,例如$_.Matches[0].Groups['filename'].Value。您不必求助于 Unix 日期格式来确保 literal 使用 /;只需\ -转义它(或使用嵌入式引用):Get-Date -Format "yyyy\/MM\/dd"
【解决方案2】:

补充Theo's helpful answer:

这不是很明显,但它是可以在ForEach-Object 脚本块中访问Select-String 命令的[命名] 捕获组匹配(不需要重复匹配-match):

PS> '... File transfer: C:\path\to\file => ...' |
      Select-String '\bFile transfer: (?<file>.+?) =>' | 
        ForEach-Object { $_.Matches[0].Groups['file'].Value }
C:\path\to\file  # Value of named capture group 'file' 
  • $_.Matches 是当前输入行的匹配集合;除非指定了-AllMatches,否则只有一个条目,索引为0。

  • .Groups 访问捕获组匹配的集合(索引 0 处的条目包含整个匹配)。

  • ['file'] 访问命名捕获组 file 的匹配项,但请注意,基于 index 的访问同样有效(对于未命名捕获组),从索引 1 开始;也就是说,上面命令中的$_.Matches[0].Groups[1].Value 会产生相同的结果。

在数据类型方面,Select-String 发出[Microsoft.PowerShell.Commands.MatchInfo] 实例,其.Matches 属性是[System.Text.RegularExpressions.Match] 实例的数组。

【讨论】:

  • 我很高兴,@aquib.rocks。我添加了一个段落,其中包含指向答案所涉及的数据类型的链接。
【解决方案3】:

下面是使用正则表达式的方法。

$var = Select-String -Path "C:\Creds\AzCopyVerbose.log" -Pattern 'Finished Transfer' | 
Select-Object -Last 20 | ForEach-Object -Process {
      $_.Line -match '\d{4}/\d{2}/\d{2}' | Out-Null
      [string]$Match = $Matches.Values
      if ([Datetime]$Match -eq (Get-Date).ToString('yyyy/MM/dd'))
      {
        $_.Line. // There is no method which I'm aware of need help in this if statement
      }
      Else {Write-Host "The date present in the azcopy verbose log is older"}
    }

【讨论】:

    猜你喜欢
    • 2011-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-09
    • 2016-01-31
    相关资源
    最近更新 更多