进度条 + ETA 与 pv 命令在同一行

Rol*_* W. 3 linux macos bash shell pv

介绍

pv在管道中使用命令来显示进度条。我用一个简单的计数器试了一下:

for (( i = 1 ; i <= 100 ; i++ )); do sleep 1; echo $i; done | pv --progress --line-mode --size 100 --eta --timer
Run Code Online (Sandbox Code Playgroud)

这工作正常,但我希望进度条显示在同一行。这个答案解释了如何做到这一点。

所以我试过这个:

for (( i = 1 ; i <= 100 ; i++ )); do sleep 1; echo $i; done | >&2 echo -en "\r"; pv --progress --line-mode --size 100 --eta --timer
Run Code Online (Sandbox Code Playgroud)

它保持在一行,但现在不再更新 ETA。

我怎样才能让 ETA 也更新?

更新

现在 iBug回答了上一节中的问题,我意识到我还有一个相关的要求:stdout需要保留以便可以在下一个管道中使用。在我的特定情况下,我需要将结果写入文件(即> some-file.txt

iBu*_*Bug 5

你输入了错误的命令。

for (( i = 1 ; i <= 100 ; i++ )); do sleep 1; echo $i; done | >&2 echo -en "\r"; pv --progress --line-mode --size 100 --eta --timer
                                                                               ^
Run Code Online (Sandbox Code Playgroud)

之前有一个分号pv,因此您实际上是在 stdin/stdout 上运行它,这是您的终端。您应该将额外的内容分组echopv让它从for循环中读取:

for (( i = 1 ; i <= 100 ; i++ )); do sleep 1; echo $i; done | (>&2 echo -en "\r"; pv --progress --line-mode --size 100 --eta --timer)
Run Code Online (Sandbox Code Playgroud)

为什么第一个命令不是这种情况?这是因为整个for do done子句被视为单个命令,因此其结果正确地通过管道传输到pv. 然而,在第二个命令中,结果通过管道传送到echo. 你知道,这echo不会从标准输入中读取任何内容。

因为pv将 stdin 定向到 stdout,所以数字也会输出到终端,这与 stderr 的指示混淆。要抑制正常输出,请将其重定向到/dev/null,因此最终命令是

for (( i = 1 ; i <= 100 ; i++ )); do sleep 1; echo $i; done | (>&2 echo -en "\r"; pv --progress --line-mode --size 100 --eta --timer) > /dev/null
Run Code Online (Sandbox Code Playgroud)

如果要将输出重定向到文件,只需/dev/null在命令末尾更改即可。