awk 输出有额外的回车符并被缓冲

awk 输出有额外的回车符并被缓冲

我的最终目标是在使用 fdkaac 编码时获得 zenity 进度对话框。

我首先从一些代码开始,当我用 lame 将“aa.wav”编码为“aa.mp3”时,这些代码可以正常工作。这会导致进度条从 0 平滑更新到 100%:

lame -m auto -V 4 aa.wav aa.mp3 | awk -vRS='\r' '(NR>3){gsub(/[()%|]/," ");print $2; fflush();}' | zenity --progress --title="Title" --text="encoding" --auto-close

现在我使用 fdkaac 运行此代码:

fdkaac --profile 2 --bitrate-mode 5 aa.wav -o aa.aac

这会导致编码结束时的屏幕输出:
[100%] 05:31.227/05:31.227 (43x), ETA 00:00.000
14607096/14607096 在 00:07.689 中处理的样本

在编码过程中,会打印第一行,并且 [100%] 在编码过程中从 0 平滑更新到 100。在编码的最后打印第二行。

基于此,我修改了 gsub 搜索并替换为: gsub(/[[%]/," ") 来挑选数据。

我现在运行这段代码:

fdkaac --profile 2 --bitrate-mode 5 aa.wav -o aa.aac 2>&1 | awk -vRS='\r' '(NR>3){gsub(/[\[%]/," ");print $1; fflush();}' | zenity --progress --title="Title" --text="Encoding" --auto-close

结果不是我所期望的。进度对话框显示为 0% ...,然后一段时间后跳至 50% ...,然后在编码完成时消失。

因此,我使用以下代码查看了进入 zenity 的数据:

fdkaac --profile 2 --bitrate-mode 5 aa.wav -o aa.aac 2>&1 | awk -vRS='\r' '(NR>3){gsub(/[\[%]/," ");print $1; fflush();}' 

屏幕输出不是我所期望的。 1 到 50 全部同时打印,但在连续行上,然后当编码完成时,50 到 100 分别打印在连续行上:

1
2
3
4
5

...

48
49
50

并继续到 50。然后输出继续在单独的行上从 50 到 100(再次同时打印):

50
51
52

..

98
99
100

所以,问题很明显......输出数据分两批打印(正如在对话框中看到的那样)。并且数据出现在连续的行上。 (awk过滤器之后的lame输出全部打印在同一行上并且平滑更新)。

我怀疑问题与额外的回车符有关,但我不知道如何摆脱它们。我尝试删除 -vRS='\r 命令..但这根本没有输出。

我不明白替换:RS='\r'。变量RS出现在哪里?

我也很奇怪,数据打印出来时正好是 50% 和 100%。为什么不是 38% 或 67%? ..所以数据告诉了我一些事情,但我不确定它是什么。

答案1

问题可能是当fdkaac它的输出到管道时缓冲它的输出。尝试在命令前加上前缀:

stdbuf -o 0 -e 0 fdkaac ... 2>&1 | ...

其中 -o 代表 stdout,-e 代表 stderr。


如果您想尝试 awk 的替代方案,可以使用 shell 脚本。确保你的 shell 是 bash

stdbuf -o 0 -e 0 fdkaac ... 2>&1 | 
(IFS="$IFS%[]"
while read -d$'\r' junk1 percent junk2
do  echo "$percent"
done) |
zenity --progress --title="Title" --text="encoding" --auto-close

通过设置 IFS(bash 字段分隔符)以包含另外 3 个字符“%[]”,它们实际上变得像输入中的空格一样,因此read带有分隔符回车符 (-d) 应该将行的第一个单词放入 var垃圾 1,百分比第二,其余的垃圾 2。然后我们可以只回显应该只保存数字的变量。

注意:您需要在没有 zenity 位的情况下尝试此操作,看看是否获得了数字字段。我不知道为什么我必须使用第一个 var junk1,因为百分比应该是该行中的第一个字段,但如果您没有得到想要的数字,请尝试从读取中删除 junk1 变量。

答案2

让我们分解一下 awk 命令: awk -vRS='\r' '(NR>3){gsub(/[()%|]/," ");print $1; fflush();}'

记录分隔符是\r,字段分隔符是[\t]+。字符 ()%|将被替换为空格。您正在占据第一个字段。

基于此格式:[100%] 05:31.227/05:31.227 (43x), ETA 00:00.000 以下内容将传递给 zenity:[100]

也许你的 awk 应该更像是: awk -vRS='\r' '(NR>3){gsub(/[()%|[]]/," ");print $1; fflush();}'

或者更好地删除位置参数:gawk -vRS='\r' 'match($0, /([0-9]+)%/, ary) {print ary[1]}'

相关内容