Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to use Select-String to print the line number and the matched value (not the line)?

Tags:

powershell

I am using powershell to search several files for a specific match to a regular expression. Because it is a regular expression, I wan't to only see what I have programmed my regex to accept, and the line number at which it is matched.

I then want to take the matched value and the line number and create an object to output to an excel file.

I can get each item in individual select string statements, but then they won't be matched up with each other

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

Can anyone help me get both the line number and the matched value?

Edit: Just to clarify what I am doing

$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
}

This still does not get anything, it just outputs a bunch of blank lines

Edit: What I am expecting to happen is for this script to search the content of all the files in the directory and find the lines that match the regular expression. Below is what I would expect for output for each file in the loop

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

File match sample:

            {
            Box = "5015",
            Description = "test box 1"
            }....
            {
            Box = "5118",
            Description = "test box 2"
            }...
            {
            Box = "5139",
            Description = "test box 3"
            }...
like image 562
HeedfulCrayon Avatar asked Oct 19 '25 18:10

HeedfulCrayon


1 Answers

Example 1

Select the LineNumber and group value for each match. Example:

$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}}

Example 2

Search *.vb and *.cs for files containing the string Box = "<n>", where <n> is some number, and output the filename, line number of the file, and the number on the box = lines. Sample code:

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]}}

This returns output like the following:

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

Example 3

Now that we know that we want the line before the match to contain {, we can use the -Context parameter with Select-String. Example:

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
      }
    }
  }
like image 175
Bill_Stewart Avatar answered Oct 22 '25 09:10

Bill_Stewart



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!