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.
CodePudding user response:
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-Content
call - Use a
Select-Object
call with the-Index
parameter to extract the lines of interest (indices are0
-based). - Use the
-replace
operator instead of-match
in 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
}
CodePudding user response:
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
$Matches
hashtable 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.