【问题标题】:Command line progress bar with other output带有其他输出的命令行进度条
【发布时间】:2015-12-19 21:34:56
【问题描述】:

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

#!/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. 如果是,请清除该行,打印输出加上换行符,然后重新打印进度条

(或者,您可以使用 ncurses)。不幸的是,这需要所有可能的东西来提供输出来打球。

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

【问题讨论】:

    标签: bash shell terminal


    【解决方案1】:

    更新: 您可以使用 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 程序示例,其中广泛使用了这些代码/序列。


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

    【讨论】:

    • 在消息前添加换行意味着进度消息永远不会被删除;我希望删除旧的进度消息。
    • 所以你想要 2 条更新线。一个用于进度,一个用于消息?
    • 不是两行更新;消息可以单调递增。我很高兴假设只会有一条进展。
    • 哦。所以你只想在进度线之前打印消息。我会更新我的答案。
    猜你喜欢
    • 2011-09-13
    • 1970-01-01
    • 2015-09-02
    • 2021-10-24
    • 2011-07-13
    • 1970-01-01
    • 2015-08-23
    • 2010-10-25
    • 1970-01-01
    相关资源
    最近更新 更多