在 Powershell 中,如何 select 字符串的不同部分并将它们分别输出到变量并显示在一行中?
In Powershell, how do you select different parts of a string and output them to variable separately and display them in line?
我正在尝试为 FFmpeg 创建一个进度条,很像 python 的 FFpb 并且已经足够远以至于我可以将 FFmpeg 的输出捕获到变量并将所需的信息保存在变量中,但只有在它之后结束。
此命令将 FFmpeg 输出的每一行作为对象保存到 $RedirectOutput
变量中:
$RedirectOutput = ffmpeg.exe -y -v quiet -stats -hide_banner -hwaccel cuda -i 'input' -c:v hevc_nvenc -preset slow -crf 18 -an -t 300 'output' 2>&1
$RedirectOutput
则变为:
frame= 124 fps=0.0 q=14.0 size= 768kB time=00:00:04.03 bitrate=1559.9kbits/s speed=8.04x
frame= 480 fps=479 q=14.0 size= 3840kB time=00:00:15.90 bitrate=1978.5kbits/s speed=15.9x
frame= 865 fps=576 q=17.0 size= 7424kB time=00:00:28.73 bitrate=2116.6kbits/s speed=19.1x
frame= 1256 fps=627 q=17.0 size= 10496kB time=00:00:41.76 bitrate=2058.7kbits/s speed=20.9x
frame= 1698 fps=678 q=16.0 size= 14080kB time=00:00:56.50 bitrate=2041.5kbits/s speed=22.6x
frame= 2074 fps=691 q=16.0 size= 17152kB time=00:01:09.03 bitrate=2035.4kbits/s speed= 23x
frame= 2515 fps=718 q=16.0 size= 20992kB time=00:01:23.73 bitrate=2053.7kbits/s speed=23.9x
frame= 2972 fps=742 q=18.0 size= 25088kB time=00:01:38.96 bitrate=2076.7kbits/s speed=24.7x
frame= 3404 fps=755 q=18.0 size= 28928kB time=00:01:53.36 bitrate=2090.4kbits/s speed=25.2x
...
这里我把每一条必要的信息保存到各自的变量中:
$videoFps = $RedirectOutput -replace "(frame=)(\s+)?(\d+)(.*)", ""
$videoFps = $RedirectOutput -replace "(.*)(fps=)(\d+)(.*)", ""
$videoSpeed = $RedirectOutput -replace "(.*)(speed=)(\d+.*)x", ""
$videoBitrate = $RedirectOutput -replace "(.*)(bitrate=)(\d+)(.*)", ""
既然已经创建了数组,我需要以格式化的方式定期将它们写入控制台(我最终会弄清楚),因为 FFmpeg 转换是 运行(而不是完成时间)和单行,但我不知道如何继续。
我是否将 FFmpeg 的输出保存到文件而不是变量并尝试从那里读取?如果是这样,我如何在每次写入后读取它?使用 while
循环?
这不会是性能问题吗?我不得不说,目前这不是我的一个大问题。只是想让它工作。
...每次写入后如何读取? 使用 ForEach-Object
循环:
ffmpeg.exe -y -v quiet -stats -hide_banner -hwaccel cuda -i 'input' -c:v hevc_nvenc -preset slow -crf 18 -an -t 300 'output' 2>&1 |
ForEach-Object {
$lineData = [psCustomObject]@{
videoFrame = $_ -replace "(frame=)(\s+)?(\d+)(.*)", ''
videoFps = $_ -replace "(.*)(fps=)(\d+)(.*)", ''
videoSpeed = $_ -replace "(.*)(speed=\s*?)(\d+.*)x", ''
videoBitrate = $_ -replace "(.*)(bitrate=)(\d+)(.*)", ''
}
$lineData | Select-Object -Property video*
Write-Progress -Activity "ffmpeg in progress: Bitrate=$($lineData.videoBitrate), Fps=$($lineData.videoFps)" -CurrentOperation "" -PercentComplete $lineData.videoSpeed -Status "Frame $($lineData.videoFrame)"
}
输出(来自给定的$RedirectOutput
数据,省略了进度条示例:):
D:\PShell\SO971642.ps1
videoFrame videoFps videoSpeed videoBitrate
---------- -------- ---------- ------------
124 0 8.04 1559
480 479 15.9 1978
865 576 19.1 2116
1256 627 20.9 2058
1698 678 22.6 2041
…
我正在尝试为 FFmpeg 创建一个进度条,很像 python 的 FFpb 并且已经足够远以至于我可以将 FFmpeg 的输出捕获到变量并将所需的信息保存在变量中,但只有在它之后结束。
此命令将 FFmpeg 输出的每一行作为对象保存到 $RedirectOutput
变量中:
$RedirectOutput = ffmpeg.exe -y -v quiet -stats -hide_banner -hwaccel cuda -i 'input' -c:v hevc_nvenc -preset slow -crf 18 -an -t 300 'output' 2>&1
$RedirectOutput
则变为:
frame= 124 fps=0.0 q=14.0 size= 768kB time=00:00:04.03 bitrate=1559.9kbits/s speed=8.04x
frame= 480 fps=479 q=14.0 size= 3840kB time=00:00:15.90 bitrate=1978.5kbits/s speed=15.9x
frame= 865 fps=576 q=17.0 size= 7424kB time=00:00:28.73 bitrate=2116.6kbits/s speed=19.1x
frame= 1256 fps=627 q=17.0 size= 10496kB time=00:00:41.76 bitrate=2058.7kbits/s speed=20.9x
frame= 1698 fps=678 q=16.0 size= 14080kB time=00:00:56.50 bitrate=2041.5kbits/s speed=22.6x
frame= 2074 fps=691 q=16.0 size= 17152kB time=00:01:09.03 bitrate=2035.4kbits/s speed= 23x
frame= 2515 fps=718 q=16.0 size= 20992kB time=00:01:23.73 bitrate=2053.7kbits/s speed=23.9x
frame= 2972 fps=742 q=18.0 size= 25088kB time=00:01:38.96 bitrate=2076.7kbits/s speed=24.7x
frame= 3404 fps=755 q=18.0 size= 28928kB time=00:01:53.36 bitrate=2090.4kbits/s speed=25.2x
...
这里我把每一条必要的信息保存到各自的变量中:
$videoFps = $RedirectOutput -replace "(frame=)(\s+)?(\d+)(.*)", ""
$videoFps = $RedirectOutput -replace "(.*)(fps=)(\d+)(.*)", ""
$videoSpeed = $RedirectOutput -replace "(.*)(speed=)(\d+.*)x", ""
$videoBitrate = $RedirectOutput -replace "(.*)(bitrate=)(\d+)(.*)", ""
既然已经创建了数组,我需要以格式化的方式定期将它们写入控制台(我最终会弄清楚),因为 FFmpeg 转换是 运行(而不是完成时间)和单行,但我不知道如何继续。
我是否将 FFmpeg 的输出保存到文件而不是变量并尝试从那里读取?如果是这样,我如何在每次写入后读取它?使用 while
循环?
这不会是性能问题吗?我不得不说,目前这不是我的一个大问题。只是想让它工作。
...每次写入后如何读取? 使用 ForEach-Object
循环:
ffmpeg.exe -y -v quiet -stats -hide_banner -hwaccel cuda -i 'input' -c:v hevc_nvenc -preset slow -crf 18 -an -t 300 'output' 2>&1 |
ForEach-Object {
$lineData = [psCustomObject]@{
videoFrame = $_ -replace "(frame=)(\s+)?(\d+)(.*)", ''
videoFps = $_ -replace "(.*)(fps=)(\d+)(.*)", ''
videoSpeed = $_ -replace "(.*)(speed=\s*?)(\d+.*)x", ''
videoBitrate = $_ -replace "(.*)(bitrate=)(\d+)(.*)", ''
}
$lineData | Select-Object -Property video*
Write-Progress -Activity "ffmpeg in progress: Bitrate=$($lineData.videoBitrate), Fps=$($lineData.videoFps)" -CurrentOperation "" -PercentComplete $lineData.videoSpeed -Status "Frame $($lineData.videoFrame)"
}
输出(来自给定的$RedirectOutput
数据,省略了进度条示例:):
D:\PShell\SO971642.ps1
videoFrame videoFps videoSpeed videoBitrate ---------- -------- ---------- ------------ 124 0 8.04 1559 480 479 15.9 1978 865 576 19.1 2116 1256 627 20.9 2058 1698 678 22.6 2041 …