【问题标题】:How to delete and replace last line in the terminal using bash?如何使用 bash 删除和替换终端中的最后一行?
【发布时间】:2011-01-24 04:34:27
【问题描述】:

我想在 bash 中实现一个显示经过秒数的进度条。为此,我需要擦除屏幕上显示的最后一行(命令“clear”会擦除整个屏幕,但我只需要擦除进度条的那一行并将其替换为新信息)。

最终结果应如下所示:

$ Elapsed time 5 seconds

然后在 10 秒后,我想将这句话(在屏幕上的同一位置)替换为:

$ Elapsed time 15 seconds

【问题讨论】:

    标签: bash replace terminal line


    【解决方案1】:

    用 \r 回车

    seq 1 1000000 | while read i; do echo -en "\r$i"; done
    

    来自人回声:

    -n     do not output the trailing newline
    -e     enable interpretation of backslash escapes
    
    \r     carriage return
    

    【讨论】:

    • for i in {1..100000}; do echo -en "\r$i"; done 避免 seq 调用 :-)
    • 这正是我所需要的,谢谢!!并且使用 seq 命令确实冻结了 termianl :-)
    • 当您使用“for i in $(...)”或“for i in {1..N}”之类的东西时,您会在迭代之前生成所有元素,这对于大型输入来说效率非常低.您可以利用管道:“seq 1 100000 | while read i; do ...”或使用 bash c 风格的 for 循环:“for ((i=0;;i++)); do ...”
    • 感谢 Douglas 和 tokland - 虽然序列制作不是问题的直接部分,但我已更改为 tokland 更高效的管道
    • 我的矩阵打印机完全弄乱了我的纸张。它总是在不再存在的同一张纸上卡点,这个程序运行多长时间?
    【解决方案2】:

    使用回车符:

    echo -e "Foo\rBar" # Will print "Bar"
    

    【讨论】:

    • 这个答案是最简单的方法。您甚至可以使用以下方法实现相同的效果: printf "Foo\rBar"
    【解决方案3】:

    回车本身只将光标移动到行首。如果每一个新的输出行至少和前一个一样长就可以了,但是如果新行更短,前一行不会被完全覆盖,例如:

    $ echo -e "abcdefghijklmnopqrstuvwxyz\r0123456789"
    0123456789klmnopqrstuvwxyz
    

    要真正清除新文本的行,您可以在\r 之后添加\033[K

    $ echo -e "abcdefghijklmnopqrstuvwxyz\r\033[K0123456789"
    0123456789
    

    http://en.wikipedia.org/wiki/ANSI_escape_code

    【讨论】:

    • 这在我的环境中非常有效。有任何兼容性方面的知识吗?
    • 在 Bash 中至少可以缩短为 \e[K 而不是 \033[K
    • 很好的答案!使用来自 ruby​​ 的 put 完美工作。现在是我工具包的一部分。
    • @The Pixel Developer:感谢您尝试改进它,但您的编辑不正确。 return 必须首先将光标移动到行的开头,然后 kill 清除从光标位置到结尾的所有内容,将整行留空,这就是意图。你把它们放在每一行的开头,类似于肯的回答,所以它写在一个空行上。
    • 记录一下,也可以\033[Gi.o. \r\033[K 之前虽然显然 \r 要简单得多。此外,invisible-island.net/xterm/ctlseqs/ctlseqs.html 提供了比维基百科更多的详细信息,并且来自 xterm 开发人员。
    【解决方案4】:

    只要线路长度不超过终端宽度,Derek Veit 的答案就可以很好地工作。如果不是这种情况,下面的代码将防止垃圾输出:

    在第一次写该行之前,做

    tput sc
    

    保存当前光标位置。现在每当你想打印你的行时,使用

    tput rc
    tput ed
    echo "your stuff here"
    

    先回到保存的光标位置,然后从光标到底部清屏,最后写入输出。

    【讨论】:

    • 奇怪,这在终结者中没有任何作用。你知道是否有兼容性限制吗?
    • Cygwin注意事项:您需要安装包“ncurses”才能使用“tput”。
    • 嗯...如果输出中多于一行,似乎不起作用。这不起作用:tput sc # save cursor echo '' > sessions.log.json while [ 1 ]; do curl 'http://localhost/jolokia/read/*:type=Manager,*/activeSessions,maxActiveSessions' >> sessions.log.json echo '' >> sessions.log.json cat sessions.log.json | jq '.' tput rc;tput el # rc = restore cursor, el = erase to end of line sleep 1 done
    • @Nux 你需要使用tput ed 而不是tput el。 @Um 的示例使用了 ed(也许他在您评论后修复了它)。
    • 仅供参考,这里是 tput 命令列表Colours and Cursor Movement With tput
    【解决方案5】:

    \033 方法对我不起作用。 \r 方法有效,但实际上并没有删除任何内容,只是将光标放在行首。因此,如果新字符串比旧字符串短,您可以在行尾看到剩余的文本。最后 tput 是最好的方法。除了光标之外,它还有其他用途,而且它预装在许多 Linux 和 BSD 发行版中,因此它应该可供大多数 bash 用户使用。

    #/bin/bash
    tput sc # save cursor
    printf "Something that I made up for this string"
    sleep 1
    tput rc;tput el # rc = restore cursor, el = erase to end of line
    printf "Another message for testing"
    sleep 1
    tput rc;tput el
    printf "Yet another one"
    sleep 1
    tput rc;tput el
    

    这是一个小倒计时脚本:

    #!/bin/bash
    timeout () {
        tput sc
        time=$1; while [ $time -ge 0 ]; do
            tput rc; tput el
            printf "$2" $time
            ((time--))
            sleep 1
        done
        tput rc; tput ed;
    }
    
    timeout 10 "Self-destructing in %s"
    

    【讨论】:

    • 这确实清除了整行,问题对我来说闪烁太多:'(
    【解决方案6】:

    如果进度输出是多行,或者脚本已经打印了换行符,您可以使用以下内容跳转行:

    printf "\033[5A"

    这将使光标向上跳5行。然后你可以覆盖任何你需要的东西。

    如果不行,你可以试试printf "\e[5A"echo -e "\033[5A",效果应该是一样的。

    基本上,使用escape sequences,您几乎可以控制屏幕上的所有内容。

    【讨论】:

    • 可移植的等价物是 tput cuu 5,其中 5 是行数(cuu 向上移动,cud 向下移动)。
    • @Maëlan 谢谢!您是否知道在运行tput cuu 5 后如何清除(“重置”)行?
    【解决方案7】:

    可以通过回车\r来实现。

    在一行代码中使用printf

    for i in {10..1}; do printf "Counting down: $i\r" && sleep 1; done
    

    echo -ne

    for i in {10..1}; do echo -ne "Counting down: $i\r" && sleep 1; done
    

    【讨论】:

      猜你喜欢
      • 2023-02-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-05
      • 1970-01-01
      • 2020-02-05
      • 1970-01-01
      • 2019-03-21
      • 2015-05-21
      相关资源
      最近更新 更多