【问题标题】:Using Select-String to Match Multiple Single-Line Patterns and Write to Output使用 Select-String 匹配多个单行模式并写入输出
【发布时间】:2019-02-01 18:51:19
【问题描述】:

我正在尝试构建一个简单的脚本来利用正则表达式并在一行上匹配多个模式 - 在整个输入文件中递归,并将结果写入输出文件。但我碰壁了:

示例文本:

BMC12345 COMBINED PHASE STATISTICS:  31 ROWS SELECTED FOR SPACE 'KDDT111D.DIH0345S', 0 ROWS SELECTED BUT DISCARDED DUE TBMC123456 COMBINED PHASE STATISTICS:  10 PHYSICAL (10 LOGICAL) RECORDS DISCARDED TO SYSDISC

这是我目前所得到的:

$table = [regex] "'.*'"
$discard = [regex] "\d* PHYSICAL"

Select-String -Pattern ($table, $discard) -AllMatches .\test.txt | foreach {
    $_.Matches.Value
} > output.txt

输出:

'KDDT111D.DIH0345S'

期望的输出:

'KDDT111D.DIH0345S' 10 Physical

由于某种原因,我无法将两种模式都写入 output.txt。 理想情况下,一旦我完成这项工作,我想使用Export-Csv 来获得一些更清洁的东西,例如:

|KDDT111D|DIH0345S|10 Physical|

【问题讨论】:

标签: regex powershell select-string


【解决方案1】:

我认为您会发现 -match 运算符更适合此操作。 [grin] 对存储在$InStuff 中的样本使用命名匹配,这...

$InStuff -match ".+SPACE '(?<Space>.+)\.(?<SubSpace>.+)'.+: (?<Discarded>.+) \(.+"

... 给出以下匹配集...

Name                           Value                                                                              
----                           -----                                                                              
Space                          KDDT111D                                                                           
SubSpace                       DIH0345S                                                                           
Discarded                      10 PHYSICAL                                                                        
0                              BMC12345 COMBINED PHASE STATISTICS: 31 ROWS SELECTED FOR SPACE 'KDDT111D.DIH0345...

可以通过$Matches.&lt;the capture group name&gt; 处理命名匹配。

【讨论】:

  • 我不相信这是我想要的方向,但我很欣赏这个想法。输入文件将包含数百条类似于我上面提供的示例文本的记录。我想让脚本从指定的目录中提取输入文件。然后,该脚本应递归提取“Space”、“SubSpace”和“Discarded”匹配值,并将每条记录的输出写入 txt/csv 文件。
  • @Jonmonjovi - 好的......但正则表达式通常是处理大文件的方式。 [grin] 我无法让 Select-String cmdlet 与您列出的模式数组一起使用。我怀疑它根本不会那样工作。 [叹息...]
  • 很遗憾,我无法使用匹配运算符和我的输入文件复制您的结果。 PS版本信息如下:PSVersion 5.1.17134.407 PSEdition Desktop PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...} BuildVersion 10.0.17134.407 CLRVersion 4.0.30319.42000 WSManStackVersion 3.0 PSRemotingProtocolVersion 2.3 SerializationVersion 1.1.0.1
  • 正则表达式可能出错的方式有很多 [grin] ...如果不查看您使用的实际代码和几行代码,讨论它几乎毫无意义实际的 [已清理] 数据文件。
【解决方案2】:

您遇到了Select-String 限制Select-String 为每个输入对象(行)发出的[Microsoft.PowerShell.Commands.MatchInfo] 对象的.Matches 属性只包含(可能是多个) 匹配传递给
-Pattern 参数的 first 正则表达式。[1]

您可以通过单个正则表达式来解决问题,通过交替组合输入正则表达式 (|):

Select-String -Pattern ($table, $discard -join '|') -AllMatches .\test.txt | 
  ForEach-Object { $_.Matches.Value } > output.txt

一个简化的例子:

# ('f.', '.z' -join '|') -> 'f.|.z'
'foo bar baz' | Select-String -AllMatches ('f.', '.z' -join '|') |
  ForEach-Object { $_.Matches.Value }

以上产出:

fo
az

证明两个正则表达式的匹配均已报告。

警告关于 输出排序:使用交替 (|) 会导致给定输入字符串的匹配项按照找到它们的顺序报告 在输入中,而不是按照正则表达式的指定顺序
也就是说,上面的-Pattern 'f.|.z'-Pattern '.z|f.' 都会产生相同的输出顺序。


[1] 从 Windows PowerShell v5.1 / PowerShell Core 6.2.0-preview.4 开始存在该问题,并在 this GitHub issue

中进行了讨论

【讨论】:

    【解决方案3】:

    感谢贡献者的想法和学习经验。我能够使用两个答案的组合获得所需的输出。

    我发现-match 运算符仅返回源文件中第一次出现的正则表达式模式匹配,因此我需要添加一个foreach 循环,以便在整个日志文件中递归返回匹配项。

    我还修改了正则表达式以仅包含大于 0 的丢弃值。

    示例文本:

    BMC51472I COMBINED PHASE STATISTICS:  0 ROWS SELECTED FOR SPACE 'KDDT000D.KDAICH0S', 0 ROWS SELECTED BUT DISCARDED DUE TOBMC51479I COMBINED PHASE STATISTICS:  0 PHYSICAL (0 LOGICAL) RECORDS DISCARDED TO SYSDISC
    BMC51472I COMBINED PHASE STATISTICS:  3499604 ROWS SELECTED FOR SPACE 'KDDT000D.KDAIND0S', 0 ROWS SELECTED BUT DISCARDED BMC51479I COMBINED PHASE STATISTICS:  0 PHYSICAL (0 LOGICAL) RECORDS DISCARDED TO SYSDISC
    BMC51472I COMBINED PHASE STATISTICS:  1 ROWS SELECTED FOR SPACE 'KDDT000D.KDCISR0S', 0 ROWS SELECTED BUT DISCARDED DUE TOBMC51479I COMBINED PHASE STATISTICS:  0 PHYSICAL (0 LOGICAL) RECORDS DISCARDED TO SYSDISC
    BMC51472I COMBINED PHASE STATISTICS:  9185775 ROWS SELECTED FOR SPACE 'KDDT000D.KDIADR0S', 0 ROWS SELECTED BUT DISCARDED BMC51479I COMBINED PHASE STATISTICS:  11 PHYSICAL (11 LOGICAL) RECORDS DISCARDED TO SYSDISC
    BMC51472I COMBINED PHASE STATISTICS:  0 ROWS SELECTED FOR SPACE 'KDDT000D.KDICHT0S', 0 ROWS SELECTED BUT DISCARDED DUE TOBMC51479I COMBINED PHASE STATISTICS:  0 PHYSICAL (0 LOGICAL) RECORDS DISCARDED TO SYSDISC
    BMC51472I COMBINED PHASE STATISTICS:  2387375 ROWS SELECTED FOR SPACE 'KDDT000D.KDICMS0S', 0 ROWS SELECTED BUT DISCARDED BMC51479I COMBINED PHASE STATISTICS:  0 PHYSICAL (0 LOGICAL) RECORDS DISCARDED TO SYSDISC
    BMC51472I COMBINED PHASE STATISTICS:  1632821 ROWS SELECTED FOR SPACE 'KDDT000D.KDIPRV0S', 0 ROWS SELECTED BUT DISCARDED BMC51479I COMBINED PHASE STATISTICS:  0 PHYSICAL (0 LOGICAL) RECORDS DISCARDED TO SYSDISC
    BMC51472I COMBINED PHASE STATISTICS:  0 ROWS SELECTED FOR SPACE 'KDDT000D.KDLADD0S', 0 ROWS SELECTED BUT DISCARDED DUE TOBMC51479I COMBINED PHASE STATISTICS:  24845 PHYSICAL (24845 LOGICAL) RECORDS DISCARDED TO SYSDISC
    

    示例:

      $regex = ".+SPACE '(?<Space>.+)\.(?<SubSpace>.+)'.+: (?<Discarded>.+) .[1-9][0-9]*\s\b"
    
        $timestamp = Get-Date
        $timestamp = Get-Date $timestamp -f "MM_dd_yy"
        $dir = "C:\Users\JonMonJovi\"
    
        cat $dir\*.log.txt | where {
            $_ -match $regex
        } | foreach {
            $Matches.Space, $Matches.SubSpace, $Matches.Discarded -join "|"
        } > C:\Users\JonMonJovi\Discarded\Discard_Log_$timestamp.txt
    

    输出:

    KDDT000D|KDIADR0S| 11 PHYSICAL
    KDDT000D|KDLADD0S| 24845 PHYSICAL
    

    从这里我可以使用管道分隔的 .txt 输出文件导入 Excel,满足我的要求。

    【讨论】:

      猜你喜欢
      • 2023-03-23
      • 2016-07-07
      • 2020-10-02
      • 1970-01-01
      • 1970-01-01
      • 2011-09-19
      • 2021-10-21
      • 2019-06-19
      • 2013-04-02
      相关资源
      最近更新 更多