'Match and $Matches in Powershell via RegEx
I have a little issue with a Powershell project, I've been working on for some time now.
The basic idea is that six iPerf speed measurements will be executed. A logfile is created to have some data which can be displayed to the user.
But there's some issue with the match and variable Matches in Powershell to display multiple values..
There's the code, I've been working on..
$1 = (Get-Content -Path 'iperf3.txt' -TotalCount 398)[-1] # Fetch details about speed measurements for download
$2 = (Get-Content -Path 'iperf3.txt' -TotalCount 796)[-1] # Fetch details about speed measurements for upload
$3 = (Get-Content -Path 'iperf3.txt' -TotalCount 1195)[-1] # Same as above
$4 = (Get-Content -Path 'iperf3.txt' -TotalCount 1593)[-1] # Same as above
$5 = (Get-Content -Path 'iperf3.txt' -TotalCount 1992)[-1] # Same as above
$6 = (Get-Content -Path 'iperf3.txt' -TotalCount 2390)[-1] # Same as above
Output via Get-Content and TotalCount
[SUM] 0.00-30.00 sec 1.09 GBytes 313 Mbits/sec receiver
[SUM] 0.00-30.00 sec 1.09 GBytes 312 Mbits/sec receiver
[SUM] 0.00-30.00 sec 1.11 GBytes 317 Mbits/sec receiver
[SUM] 0.00-30.00 sec 1.09 GBytes 311 Mbits/sec receiver
[SUM] 0.00-30.00 sec 1.11 GBytes 317 Mbits/sec receiver
[SUM] 0.00-30.00 sec 1.09 GBytes 312 Mbits/sec receiver
Afterwards, I use the RegEx and Variable to output the numbers before Mbits/sec and include Mbits/sec from this line of code..
$1 -match '\d+\sMbits[/]sec'
$2 -match '\d+\sMbits[/]sec'
etc.
I do variable Matches to validate that the Variable is True, and receive the output of 312 Mbits/sec, but nothing more.
Now this is where I cannot see the fault in the code. The variable passed and it's true, but I only have one Value as 313 Mbits/sec via Value.
I figured that I would see both 313 Mbits/sec and 312 Mbits/sec in the output/value prompt.
Did I do something wrong while using the match/Matches variable/function?
Any feedback and/or suggestions will be appreciated.
Solution 1:[1]
The automatic $Matches variable only ever reflects the results of the most recent -match operation - and then only if (a) the matching was successful and (b), fundamentally, only if the LHS was a single string - if the LHS was a collection (array), -match acts as a filter, returning the subarray of matching elements, and does not populate $Matches.
However, your command can be greatly streamlined:
- Use a single
Get-Contentcall - Use a
Select-Objectcall with the-Indexparameter to extract the lines of interest (indices are0-based). - Use the
-replaceoperator instead of-matchin order to directly extract the substrings of interest:
(
Get-Content 'iperf3.txt' | Select-Object -Index 397,795,1194,1592,1991,2389
) -replace '.+\b(\d+\sMbits/sec).+', '$1'
Taking a step back:
Instead of selecting the lines of interest by fixed indices (line numbers), select them by regexes too, which allows you to use a single Select-String call:
Select-String -LiteralPath 'iperf3.txt' -Pattern '\s*\[SUM].+\b(\d+\sMbits/sec).+' |
ForEach-Object {
$_.Matches.Groups[1].Value
}
Solution 2:[2]
You didn't do anything wrong it's just the default behavior for the -match operator and how the $Matches automatic variable is populated.
Here is an extract from Matching operators that explains very well how it works:
It is important to note that the
$Matcheshashtable contains only the first occurrence of any matching pattern.
You have 2 workarounds, the first one could be using Regex.Matches Method to find all appearances of the matched pattern:
$string = @'
[SUM] 0.00-30.00 sec 1.09 GBytes 313 Mbits/sec receiver
[SUM] 0.00-30.00 sec 1.09 GBytes 312 Mbits/sec receiver
[SUM] 0.00-30.00 sec 1.11 GBytes 317 Mbits/sec receiver
[SUM] 0.00-30.00 sec 1.09 GBytes 311 Mbits/sec receiver
[SUM] 0.00-30.00 sec 1.11 GBytes 317 Mbits/sec receiver
[SUM] 0.00-30.00 sec 1.09 GBytes 312 Mbits/sec receiver
'@
[regex]::Matches($string, '\d+\sMbits[/]sec').Value
Note that, in above example, $string is a multi-line string, however in the example it will be an array since it requires a loop.
$string = @'
[SUM] 0.00-30.00 sec 1.09 GBytes 313 Mbits/sec receiver
[SUM] 0.00-30.00 sec 1.09 GBytes 312 Mbits/sec receiver
[SUM] 0.00-30.00 sec 1.11 GBytes 317 Mbits/sec receiver
[SUM] 0.00-30.00 sec 1.09 GBytes 311 Mbits/sec receiver
[SUM] 0.00-30.00 sec 1.11 GBytes 317 Mbits/sec receiver
[SUM] 0.00-30.00 sec 1.09 GBytes 312 Mbits/sec receiver
'@ -split '\r?\n'
foreach($line in $string) {
if($line -match '\d+\sMbits[/]sec') {
$Matches[0]
}
}
GitHub issue #7867 proposes to add a -matchall operator to PowerShell, if you believe it would be helpful consider up-voting it.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | |
| Solution 2 | Santiago Squarzon |
