【问题标题】:Is there a way to use Select-String to print the line number and the matched value (not the line)?有没有办法使用 Select-String 打印行号和匹配值(不是行)?
【发布时间】:2017-10-28 03:02:56
【问题描述】:

我正在使用 powershell 搜索多个文件以查找与正则表达式的特定匹配。因为它是一个正则表达式,我不想只看到我编写的正则表达式接受的内容,以及匹配的行号。

然后我想获取匹配的值和行号并创建一个对象以输出到 excel 文件。

我可以在单独的选择字符串语句中获取每个项目,但是它们不会相互匹配

Select-String -Path $pathToFile -Pattern '(?<={\n\s*Box\s=\s")14\d{3}(?=",)' | 
    Select LineNumber, Matches.Value 
#Will only print out the lineNumber

Select-String -Path $pathToFile -Pattern '(?<={\n\s*Box\s=\s")14\d{3}(?=",)' | 
    Foreach {$_.matches} | Select value 
#Will only print matched value and can't print linenumber

谁能帮我获取行号和匹配值?

编辑:只是为了澄清我在做什么

$files = Get-ChildItem $directory -Include *.vb,*.cs -Recurse
$colMatchedFiles = @()
foreach ($file in $files) {
    $fileContent = Select-String -Path $file -Pattern '(?<={\n\s*Box\s=\s")14\d{3}(?=",)' |
        Select-Object LineNumber, @{Name="Match"; Expression={$_.Matches[0].Groups[1].Value}}
    write-host $fileContent #just for checking if there is anything
}

这仍然没有得到任何东西,它只是输出了一堆空行

编辑:我期望这个脚本搜索目录中所有文件的内容并找到与正则表达式匹配的行。以下是我期望循环中每个文件的输出

LineNumber Match
---------- -----
324        15
582        118
603        139
...        ...

文件匹配示例:

            {
            Box = "5015",
            Description = "test box 1"
            }....
            {
            Box = "5118",
            Description = "test box 2"
            }...
            {
            Box = "5139",
            Description = "test box 3"
            }...

【问题讨论】:

  • 好的。现在:你想提取什么文本? Box = "之后的数字?
  • 文件匹配示例上方的预期输出是我想要的。我想要箱号的最后 3 位数字。我不介意盒子号码的所有数字。我可以弄清楚正则表达式,它只是得到匹配的行号和匹配的值
  • 好的,我们终于得到了你想要的。请参阅我的答案中的示例 2。
  • 请参阅更新答案中的示例 3 - 仅输出匹配项,其中每个匹配项之前的行包含 { 字符。经验教训:准确解释您希望正则表达式做什么。

标签: powershell


【解决方案1】:

示例 1

为每个匹配项选择LineNumber 和组值。示例:

$sampleData = @'
prefix 1 A B suffix 1
prefix 2 A B suffix 2
'@ -split "`n"

$sampleData | Select-String '(A B)' |
    Select-Object LineNumber,
    @{Name="Match"; Expression={$_.Matches[0].Groups[1].Value}}

示例 2

在 *.vb 和 *.cs 中搜索包含字符串 Box = "&lt;n&gt;" 的文件,其中 &lt;n&gt; 是某个数字,并输出文件名、文件的行号以及 box = 行上的数字。示例代码:

Get-ChildItem $pathToFiles -Include *.cs,*.vb -Recurse |
  Select-String 'box = "(\d+)"' |
    Select-Object Path,
    LineNumber,
    @{Name="Match"; Expression={$_.Matches[0].Groups[1].Value -as [Int]}}

这会返回如下输出:

Path             LineNumber Match
----             ---------- -----
C:\Temp\test1.cs          2  5715
C:\Temp\test1.cs          6  5718
C:\Temp\test1.cs         10  5739
C:\Temp\test1.vb          2  5015
C:\Temp\test1.vb          6  5118
C:\Temp\test1.vb         10  5139

示例 3

现在我们知道我们希望匹配前的行包含{,我们可以将-Context 参数与Select-String 一起使用。示例:

Get-ChildItem $pathToFiles -Include *.cs,*.vb -Recurse |
  Select-String 'box = "(\d+)"' -Context 1 | ForEach-Object {
    # Line prior to match must contain '{' character
    if ( $_.Context.DisplayPreContext[0] -like "*{*" ) {
      [PSCustomObject] @{
        Path = $_.Path
        LineNumber = $_.LineNumber
        Match = $_.Matches[0].Groups[1].Value
      }
    }
  }

【讨论】:

  • Matches 的结构是什么?我对为什么在查看 Matches $_.Matches[0].Groups[1].Value 时访问数组感到困惑
  • Matches 数组是MatchInfo 对象的集合。为了获得第一个匹配的子字符串,我们从第二组中获取第一个匹配的值。 (第一组是整个匹配字符串。)
  • 见我上面的编辑。出于某种原因,你所拥有的工作,但不适用于我正在做的事情......我真的不明白为什么
  • 请更新您的问题以提供您想要匹配的示例文件名、您想要捕获的子字符串以及输出应该是什么样子。
  • 已更新。我期望的输出与您的示例完全相同,我只是遍历多个文件并输出结果
猜你喜欢
  • 1970-01-01
  • 2022-12-11
  • 2015-03-17
  • 2014-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-24
相关资源
最近更新 更多