116

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

最终结果应如下所示:

$ Elapsed time 5 seconds

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

$ Elapsed time 15 seconds
4

8 回答 8

210

回车本身仅将光标移动到行首。如果每一个新的输出行至少和前一个一样长,那没关系,但如果新行较短,前一行不会被完全覆盖,例如:

$ echo -e "abcdefghijklmnopqrstuvwxyz\r0123456789"
0123456789klmnopqrstuvwxyz

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

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

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

于 2011-07-21T10:06:36.580 回答
124

用 \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
于 2010-03-05T16:08:38.650 回答
23

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

在第一次写这行之前,做

tput sc

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

tput rc
tput ed
echo "your stuff here"

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

于 2013-09-20T12:04:48.060 回答
14

\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"
于 2015-01-14T20:45:22.183 回答
12

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

printf "\033[5A"

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

如果这不起作用,您可以尝试printf "\e[5A"or echo -e "\033[5A",它应该具有相同的效果。

基本上,使用转义序列,您几乎可以控制屏幕上的所有内容。

于 2017-05-19T22:16:12.443 回答
4

使用回车符:

echo -e "Foo\rBar" # Will print "Bar"
于 2010-03-05T16:09:25.717 回答
2

可以通过放置回车来实现\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
于 2018-09-27T04:59:57.513 回答
0

如果您只想清除前一行,以下可能会解决问题。

printf '\033[1A\033[K'

对于多行,在循环中使用它:

for i in {1..10}; do
    printf '\033[1A\033[K'
done

这将清除最后 10 行。

于 2022-02-27T16:00:56.423 回答