命令行进度条与其他输出

时间:2015-12-19 21:34:57

标签: bash shell terminal

在命令行上获取进度条的一种流行方法是使用回车符,它会覆盖前一行,如下所示:

#!/bin/bash
echo -ne '[#   ] 25%\r'
sleep 1
echo -ne '[##  ] 50%\r'
sleep 1
echo -ne '[### ] 75%\r'
sleep 1
echo -ne '[####] 100%\r'

这没关系......如果您只想要打印进度条。但是更复杂的脚本可能需要打印进度条,同时还输出诊断输出。您希望命令行应用程序的缓冲区演变如下(以----分隔):

[#   ] 25%
----
msg1
[#   ] 25%
----
msg1
msg2
[#   ] 25%
----
msg1
msg2
[##  ] 50%

等。现在,流行的方法失败了:

#!/bin/bash
echo -ne '[#   ] 25%\r'
echo "msg 1"
sleep 1
echo "msg 2"
echo -ne '[##  ] 50%\r'
echo "msg 3"
sleep 1
echo "msg 4"
echo -ne '[### ] 75%\r'
sleep 1
echo -ne '[####] 100%\r'

输出

ezyang@sabre:~$ ./test.sh 
msg 1] 25%
msg 2
msg 3] 50%
msg 4

似乎要实现这一点,任何其他时间要打印邮件,您需要:

  1. 检查它是否为进度条,
  2. 如果是,请清除该行,打印输出和换行符,然后重新打印进度条
  3. (或者,您可以使用ncurses)。不幸的是,这需要一切可能让输出发挥作用的东西。

    是否有任何模块化方法可以使这种进度条工作,这不需要检测所有其他输出到终端的方法?

1 个答案:

答案 0 :(得分:3)

<强>更新: 您可以使用ANSI / VT100转义码/序列执行此操作。

在添加工作示例之前,您需要了解以下内容:

  • 您需要确保输出到TTY /控制台。

  • 您需要了解IO(stdout / stderr)之间的区别 线和TTY线。 \r会将您带到IO行的开头,即使该行跨越多条TTY行。

  • Windows控制台中不支持这些代码/序列。但您可以在ConEmu(推荐)或ansicon中使用它们。

这是一个工作示例。代码应该是不言自明的:

 #!/bin/bash

 ERASE_SCREEN_AFTER="\033[0J"
 ERASE_LINE_BEFORE="\033[1K"
 ERASE_LINE_AFTER="\033[0K"
 UP="\033[1A"

 up_count=2
 messages="\n"
 progress=""

 echo_repeat() {
   c="$2"
   while (( c )); do
     echo -en "$1"
     (( c-- ))
   done
 }

 update_status() {
   echo_repeat "$UP" "$up_count"
   echo -en "$ERASE_LINE_BEFORE" "$ERASE_SCREEN_AFTER" "\r"
   echo -en "$messages"
   echo "$progress"
 }

 add_msg() {
   messages+="$@\n"
   update_status
   (( up_count++ ))
 }

 set_progress() {
   progress="$@"
   update_status
 }

 echo_repeat "\n" $up_count

 set_progress '[#   ] 25%'
 add_msg "msg 1"
 sleep 1

 add_msg "msg 2"
 set_progress '[##  ] 50%'
 add_msg "msg 3"
 sleep 1

 add_msg "msg 4"
 set_progress '[### ] 75%'
 sleep 1

 set_progress '[####] 100%'

您可以单独使用这些代码/序列,而无需使用 (n)的诅咒。这包括设置前景/背景颜色,使用粗体字体以及其他功能。

saldl是CLI程序的一个示例,其中广泛使用这些代码/序列。

旧答案(已废弃):如果我正确理解您的问题,您只需在\n行之前添加msg