【问题标题】:Scanning a .log for specific strings in latest lines using Powershell使用 Powershell 扫描 .log 以查找最新行中的特定字符串
【发布时间】:2020-07-17 09:01:15
【问题描述】:

我有一个 .log 文件,它不断向自己添加行,我正在尝试制作一个 Powershell 脚本,当在 .log 文件的最新行中检测到相应的字符串时,它将启动两个批处理脚本中的一个。到目前为止,这是我所拥有的:

while ($True) {
    Write-Output 'Enter <ctrl><c> to break out of this loop.'
    Start-Sleep -Seconds 1
    Copy-Item -LiteralPath "C:\LocationOfFile\latest.log" -Destination "C:\Users\Diogo\Desktop\Detector"
    Rename-Item -Path "C:\Users\Diogo\Desktop\Detector\latest.log" -NewName "latest.txt"
    Get-Content -Path "latest.txt" -tail 1 -wait | Select-String -Quiet '§6§lP§e§lrof'
    if (System.Boolean -eq True) {
        Invoke-Item result1.bat
        Read-Host -Prompt "Press Enter to continue"
    }
    else {
        Get-Content -Path "latest.txt" -tail 1 -wait | Select-String -Quiet 'spawned'
        if (System.Boolean -eq True) {
            Invoke-Item result2.bat
            Read-Host -Prompt "Press Enter to continue"
        }
        else {
        }
    }
}

我首先从它的位置复制 .log 文件并将其更改为 .txt。 然后我搜索字符串(“§6§lP§e§lrof”和“spawned”) 最后我试着让它重新做一遍,但这似乎不像搜索那样有效。

有什么帮助吗? 提前感谢

编辑:

非常感谢您的全面回复,这确实帮助我掌握了一些 Powershell 概念,并且运行良好。第二个脚本有点矫枉过正,实际上我遇到了完全相反的问题:添加的线条非常缓慢。在一个完美的世界中,我希望脚本在找到一个结果后继续运行,而不是在找到每个结果后继续重置它。关于日志文件还有另一条非常有趣的规则:带有我所追求的字符串的行永远不会一个接一个地出现,至少在它们之间总是有一个。这意味着如果脚本连续两次找到相同的字符串,它只是同一行,我不希望我的批处理脚本停止。我现在正在使用的 PowerShell 脚本(这是您向我展示的代码,对其进行了微小的更改以使其循环)在最后,它只使用了一个小问题:如果我将计算机用于其他 Powershell当它找到结果时变成顶部的窗口,我不希望这种情况发生,你能帮我做最后一件事吗?非常感谢您!

while ($True) {
    Write-Output 'Enter <ctrl><c> to break out of this loop.'
    Start-Sleep -Seconds 1
    $LastLogLine = Get-Content -Path "C:\LocationOfFile\latest.log" -tail 1
    if ($LastLogLine -ne $LastLine) {
        if ($LastLogLine -like '*§6§lP§e§lrof*') {
            Start-Process -FilePath "result1.bat" -WindowStyle Minimized
            $LastLine = $LastLogLine
      } elseif ($LastLogLine -like '*spawned*') {
            Start-Process -FilePath "result2.bat" -WindowStyle Minimized
            $LastLine = $LastLogLine
            }
    }
}

【问题讨论】:

    标签: powershell


    【解决方案1】:

    首先,您的脚本无法运行有两个原因:

    • Get-Content -Path "latest.txt" -tail 1 -wait | Select-String -Quiet '§6§lP§e§lrof' Get-Content -Wait 将继续运行,只要它读取的文件存在或直到它被 Ctrl-C'd,所以你的脚本永远不会超出这个范围。您可以在此处删除 -Wait
    • if (System.Boolean -eq True) 我看不出你想在这里做什么。从之前的 Select-String 收集结果? Select-String 不会自行设置任何变量或标志。此外,您正在将类型与字符串进行比较:您在问“布尔值的概念是否等于字符串 'True' ?”。您可以做的是存储 Select-String 的结果,然后执行 if ($Result -eq $True)(强调 $True,而不是“True”)。

    此外,我会在您的脚本中重写或更正几件事:

    • Copy-Item每秒:有必要吗?为什么不直接读取原始文件并将其存储在变量中?如果只是这样,您可以将扩展名从 .log 更改为 .txt,请知道 powershell 并不关心扩展名,并且会愉快地阅读任何内容。
    • Select-String:您是否考虑过只使用比较运算符-like,如if ($MyString -like "*$MyKeyword*") {...}
    • 如果块不需要 Else 块。如果你的 Else 什么都不做,你可以不写它。还有一个 elseif 块,您可以使用它来代替链接 else 和 if。
    • 代码风格:请选择indentation style并坚持下去。我最常看到的是 1TBS,但 K&R 或 Allman 也很有名。我可能会或可能不会要求编辑以对您的问题进行缩进:p

    所以,我们最终得到了这个:

    while ($True) {
        Write-Output 'Enter <ctrl><c> to break out of this loop.'
        Start-Sleep -Seconds 1
        $LastLogLine = Get-Content -Path "C:\LocationOfFile\latest.log" -tail 1
        if ($LastLogLine -like '*§6§lP§e§lrof*') {
            Invoke-Item result1.bat
            Read-Host -Prompt "Press Enter to continue"
        } elseif ($LastLogLine -like '*spawned*') {
            Invoke-Item result2.bat
            Read-Host -Prompt "Press Enter to continue"
        }
    }
    

    但是,如果写入日志的程序的写入速度快于您处理行的速度(包括批处理脚本),这将不起作用。如果这样做,您的脚本将跳过行,因为您只处理最后一行。如果写了两行,您将看不到倒数第二行。

    为了解决这个问题,我们可以使用 Powershell 作业做一些异步魔法,我们将能够看到自上次循环以来写入的所有行,无论是写入的 1 行、0 行还是 100 行。 about_jobs 是 Powershell 作业和异步操作的非常好的入门读物,请阅读。

      $stream = Start-Job -ArgumentList $LogPath -Name "StreamFileContent" -ScriptBlock {Get-Content $args -Wait}
      Receive-Job -Job $Stream                              # Discard everything that was already written in the file, we only want the stuff that is added to the file after we've started.
      while($true) {                                        # As long as the script is left running
          foreach($NewLine in (Receive-Job -Job $stream)) { # Fetch the lines that Get-Content gave us since last loop
              if ($NewLine -like '*§6§lP§e§lrof*') {        # Check for your keyword
                  C:\MyScriptPath\MyScript1.bat             # Start batch script
              } elseif ($NewLine -like '*spawned*') {
                  C:\MyScriptPath\MyScript2.bat
              }
          }
      }
    

    【讨论】:

    • 非常感谢您的全面回复,这确实帮助我掌握了一些 Powershell 概念并且它完美地工作。你能帮我解决关于这个脚本的最后一个问题吗?不管怎样,非常感谢!这对我学习 PowerShell 帮助很大!
    猜你喜欢
    • 1970-01-01
    • 2023-04-05
    • 2021-04-02
    • 2018-09-23
    • 1970-01-01
    • 2023-03-24
    • 1970-01-01
    • 2017-05-01
    • 1970-01-01
    相关资源
    最近更新 更多