4

I have a report file that is generated and containes various file references. I am using Select-String and regular expressions to match on certain types of files and perform subsequent processing on them.

the dilemma I have is trying to consistently identify the number of matches when there are zero (0), one (1), or more than one (2+) matches. Here is what I've tried:

(select-string -path $outputfilePath -pattern $regex -allmatches).matches.count

This return "null" if there are 0 matches, "1" if one match, and "null" if more than one match.

(select-string -path $outputfilePath -pattern $regex -allmatches).count

this return "null" if there are 0 or 1 match and the number of matches if more than one match.


I'm faily new to Powershell, but am trying to find a consistent way to test on the number of matches regardless of whether there are 0, 1, or more than 1 match.

j0k
  • 22,600
  • 28
  • 79
  • 90
  • Can you post sample data which is causing this inconsistent behavior? – Mitul Sep 04 '13 at 20:49
  • Just going to throw my voice in here since I can't contest a flag, but I disagree with migration for this topic. There is more going on here than the behavior of Select-String -- the problem involves an elaboration on Collections and some .NET classes. It would be appropriate on both, but it has sufficient programming context to be appropriate on SO, per these meta posts: [1](http://meta.stackexchange.com/questions/170798/request-for-question-migration-reversal/170800#170800), [2](http://meta.stackexchange.com/questions/32471/wondering-why-i-was-migrated/32472#32472). – Anthony Neace Sep 05 '13 at 17:30
  • @HyperAnthony - I've retracted my "migrate" vote. You are correct - the gist of this question would seem to fit within the scope of this site. – JDB Sep 05 '13 at 17:59
  • @Cyborgx37 Thanks, apologies if I've seemed overly-hostile or defensive both here and on Meta. I'll keep your comments in mind as I continue to collect feedback on tagging (and site scope) in powershell-related topics. – Anthony Neace Sep 05 '13 at 18:04

2 Answers2

6

Try this:

$content = Get-Content $outputfilePath
($content -match $regex).Count

Powershell has a number of Comparison Operators that will probably make your life easier. Here's a quick listing:

-eq
-ne
-gt
-ge   
-lt
-le
-Like
-NotLike
-Match
-NotMatch
-Contains
-NotContains
-In
-NotIn
-Replace

In this instance, -Match will match the $content string against your regular expression $regex, and the output is grouped by parenthesis. This grouping is a collection of strings. We can then Count the objects and print out an accurate count of matches.

So why doesn't your code work as expected? When you have a single match, .Matches actually returns a System.Text.RegularExpressions.Match object that looks something like this for a string "test123":

Groups   : {test123}
Success  : True
Captures : {test123}
Index    : 15
Length   : 7
Value    : test123

Why does this happen? Because a Microsoft.PowerShell.Commands.MatchInfo object is what Select-String returns. You can verify this by attempting some other properties like .Filename on your single-match output.

Okay, but why can't we get all of our matches in one go? This is because multiple matches will return multiple objects, so now you have a collection that you're trying to operate on. The collection has a different type, and doesn't understand .Matches. No collection is returned on 1 match, but instead a single object that does understand .Matches is!

Long story short: these aren't the outputs you're looking for!

Anthony Neace
  • 25,013
  • 7
  • 114
  • 129
2

You can use the array sub-expression operator @(...) to always place results in a collection with a Count:

(Select-String ...)        # may return $null, one match, or a collection of matches
(Select-String ...).Count  # only succeeds for two or more matches

@(Select-String ...)       # always returns a collection of matches
@(Select-String ...).Count # always succeeds
Emperor XLII
  • 13,014
  • 11
  • 65
  • 75