Skyler
Skyler

Reputation: 1199

How do I return only the matching regular expression when I select-string(grep) in PowerShell?

I am trying to find a pattern in files. When I get a match using Select-String I do not want the entire line, I just want the part that matched.

Is there a parameter I can use to do this?

For example:

If I did

select-string .-.-.

and the file contained a line with:

abc 1-2-3 abc

I'd like to get a result of just 1-2-3 instead of the entire line getting returned.

I would like to know the Powershell equivalent of a grep -o

Upvotes: 70

Views: 125025

Answers (8)

Carl Walsh
Carl Walsh

Reputation: 6999

Instead of piping to % or select you can use simpler .prop Member Enumeration syntax, which magically works on multiple elements:

(Select-String .-.-. .\test.txt -All).Matches.Value

or less parentheses:

$m = Select-String .-.-. .\test.txt -All
$m.Matches.Value

Upvotes: 15

Adrien Constant
Adrien Constant

Reputation: 341

If you don't want to use ForEach operator, you can only use pipes and Select -Expand

For example, to get only the path after C:\, you could use :

Get-ChildItem | Select-String -Pattern "(C:\\)(.*)" | Select -Expand Matches | Select -Expand Groups | Where Name -eq 2 | Select -Expand Value

Where Name -eq 2 only selects the second match of the regex pattern specified.

Upvotes: 7

7r4c0r
7r4c0r

Reputation: 321

None of the above answers worked for me. The below did.

Get-Content -Path $pathToFile | Select-String -Pattern "'test\d'" | foreach {$_.Matches.Value}

Get-Content -Path $pathToFile | # Get-Content will divide into single lines for us

Select-String -Pattern "'test\d'" | # Define the Regex

foreach {$_.Matches.Value} # only return the value of the Object's Matches field. (This allows for multiple result matches.)

Upvotes: 13

Jaykul
Jaykul

Reputation: 15824

In the spirit of teach a man to fish ...

What you want to do is pipe the output of your select-string command into Get-member, so you can see what properties the objects have. Once you do that, you'll see "Matches" and you can select just that by piping your output to | **Select-Object** Matches.

My suggestion is to use something like: select linenumber, filename, matches

For example: on stej's sample:

sls .\test.txt -patt 'test\d' -All |select lineNumber,fileName,matches |ft -auto

LineNumber Filename Matches
---------- -------- -------
         1 test.txt {test1, test2, test3}
         2 test.txt {test3, test4}
         3 test.txt {test2}

Upvotes: 16

Keith Hill
Keith Hill

Reputation: 202052

Or just:

Select-String .-.-. .\test.txt -All | Select Matches

Upvotes: 42

stej
stej

Reputation: 29479

I tried other approach: Select-String returns property Matches that can be used. To get all the matches, you have to specify -AllMatches. Otherwise it returns only the first one.

My test file content:

test test1 alk atest2 asdflkj alj test3 test
test test3 test4
test2

The script:

select-string -Path c:\temp\select-string1.txt -Pattern 'test\d' -AllMatches | % { $_.Matches } | % { $_.Value }

returns

test1 #from line 1
test2 #from line 1
test3 #from line 1
test3 #from line 2
test4 #from line 2
test2 #from line 3

Select-String at technet.microsoft.com

Upvotes: 35

Steven Murawski
Steven Murawski

Reputation: 11255

David's on the right path. [regex] is a type accelerator for System.Text.RegularExpressions.Regex

[regex]$regex = '.-.-.'
$regex.Matches('abc 1-2-3 abc') | foreach-object {$_.Value}
$regex.Matches('abc 1-2-3 abc 4-5-6') | foreach-object {$_.Value}

You could wrap that in a function if that is too verbose.

Upvotes: 40

David McEwing
David McEwing

Reputation: 3340

You can use the System.Text.RegularExpressions namespace:

http://msdn.microsoft.com/en-us/library/system.text.regularexpressions.regex.aspx

Upvotes: 2

Related Questions