I will be reading a text files and filtered it to the lines that I only need, then using regex to extract the content. After that, I would be finding the value that is smaller than certain value and get its index. With that index I'll be repeat be repeating the steps mentioned and extract another matches. I stuck at after getting the group of the matches. How do I proceed? Example below is only a line of the text file for easy of explanation.
$content=Get-Content -Path "C:\log.txt"
$content | Select-String -Pattern 'encoded' | ForEach-Object {
if($_ -match "(.*) ([0-9]*) (.*),(.*)"){
$Matches[2]
}
}
$Matches[2] would be something like:
0 66785 3434 125 0 24324 0 55
I'm trying to get the index of the value that's smaller than 30, so that I could extract the next information I want from another regex matching of the same file.
$content=Get-Content -Path "C:\log.txt"
$content | Select-String -Pattern 'Input' | ForEach-Object {
if($_ -match "(.*) '(.*)':"){
$Matches[2]
# How do I extract the content of the $Matches[2] here from the previously obtained indexes?
}
}
Thanks in advance! Appreciate any help!
Some of the input file content. The real file would have repeated blocks of this:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'C:\myvideo.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf54.63.104
Output #0, mp4, to 'C:\output\myvideo.mp4':
Metadata:
encoder : Lavf58.15.100
Stream #0:0(und): Video: hevc (Main 10) (hev1 / 0x31766568), yuv420p10le(progressive), 864x480, q=2-31, 12800 tbn (default)
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp (default)
Metadata:
encoded 2058 frames, 1376.59 fps, 373.36 kbps, 3.66 MB
There is a misconception in the question. $matches[2] would not be an array of values you need to index. It would represent a scalar value for each interation of the foreach-object block. Those results are all sent down the pipeline individually.
I would still like to answer the question as stated though. Given an array of values, determine which of those is below a threshold and return the index of its position in the array.
$results = $content | Select-String -Pattern 'encoded' |
Where-object{$_ -match "(.*) ([0-9]*) (.*),(.*)"} |
ForEach-Object{$Matches[2]}
This is similar to the code you show above. It saves the values into an array called $results.
$threshold = 30
for($index=0; $index -lt $results.count; $index++){
if([int]$results[$index] -lt $threshold){
Write-Host "The value at index $index is $($results[$index]) which is below $threshold"
}
}
Then we cycle the array elements, one by one, using a counter. Check every value and report the index we were currently at.
Given the scenario, I would go a different route altogether
I would like to take this in a slightly different direction. Understanding that each file with have multiple blocks like you show in the question that will correspond to multiple files you are processing and you are only interested in files where there are less than 30 encoded frames.
Note: This solution is heavily dependent on how the real data looks. I can only go on based what is in the question. If the real data deviates too much from that the solution is not guaranteed to work or give expected results.
Using [regex] lets split the file into its chunks. Using names capture groups we can pull just the values from each "block" that you want. Non-greedy captures will ensure we don't match outside of any given block. Then we make custom objects that we can filter just like you would normal PowerShell objects.
If the file called C:\log.txt looked like this:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'C:\myvideo.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf54.63.104
Output #0, mp4, to 'C:\output\myvideo.mp4':
Metadata:
encoder : Lavf58.15.100
Stream #0:0(und): Video: hevc (Main 10) (hev1 / 0x31766568), yuv420p10le(progressive), 864x480, q=2-31, 12800 tbn (default)
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp (default)
Metadata:
encoded 2058 frames, 1376.59 fps, 373.36 kbps, 3.66 MB
Input #1, mov,mp4,m4a,3gp,3g2,mj2, from 'C:\myvideo2.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf54.63.104
Output #0, mp4, to 'C:\output\myvideo2.mp4':
Metadata:
encoder : Lavf58.15.100
Stream #0:0(und): Video: hevc (Main 10) (hev1 / 0x31766568), yuv420p10le(progressive), 864x480, q=2-31, 12800 tbn (default)
Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, stereo, fltp (default)
Metadata:
encoded 0 frames, 1376.59 fps, 373.36 kbps, 3.66 MB
We could run this:
$content = Get-Content -Path "C:\log.txt" -Raw
[regex]::Matches($content,"(?sm)Input #(?<number>\d+).*?from '(?<filename>.*?)'.*?encoded (?<frames>\d+)") | ForEach-Object{
[pscustomobject]@{
Index = $_.Groups["number"].Value
Filename = $_.Groups["filename"].Value
EncodedFrames = [int]$_.Groups["frames"].Value
}
}
On its own would return
Index Filename EncodedFrames
----- -------- -------------
0 C:\myvideo.mp4 2058
1 C:\myvideo2.mp4 0
So lets filter that output. Add onto the last line the following i.e. after the Foreach block ending parentheses: | Where-Object{$_.EncodedFrames -lt 30} and you would get just the ones you want. Then you could add | Select-Object -expand Filename to just get those file names.
All together now
$content = Get-Content -Path "C:\log.txt" -Raw
[regex]::Matches($content,"(?sm)Input #(?<number>\d+).*?from '(?<filename>.*?)'.*?encoded (?<frames>\d+)") | ForEach-Object{
[pscustomobject]@{
Index = $_.Groups["number"].Value
Filename = $_.Groups["filename"].Value
EncodedFrames = [int]$_.Groups["frames"].Value
}
} | Where-Object{$_.EncodedFrames -lt 30} | Select-Object -expand Filename
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With