如何使用bash删除和替换终端中的最后一行?

Deb*_*ger 90 bash terminal replace line

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

最终结果应如下所示:

$ Elapsed time 5 seconds
Run Code Online (Sandbox Code Playgroud)

然后在10秒后我想通过以下方式替换这句话(在屏幕中的相同位置):

$ Elapsed time 15 seconds
Run Code Online (Sandbox Code Playgroud)

Der*_*eit 178

回车本身仅将光标移动到行的开头.如果每个新的输出行至少与前一行一样长,那就没关系,但如果新行更短,则前一行不会被完全覆盖,例如:

$ echo -e "abcdefghijklmnopqrstuvwxyz\r0123456789"
0123456789klmnopqrstuvwxyz
Run Code Online (Sandbox Code Playgroud)

要实际清除新文本的行,可以在以下\033[K后添加\r:

$ echo -e "abcdefghijklmnopqrstuvwxyz\r\033[K0123456789"
0123456789
Run Code Online (Sandbox Code Playgroud)

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

  • 在Bash中至少可以缩短为`\ e [K`而不是`\ 033 [K`. (19认同)
  • 这在我的环境中非常有效.有兼容性的知识吗? (3认同)

Ken*_*Ken 109

用\ r回显回车

seq 1 1000000 | while read i; do echo -en "\r$i"; done
Run Code Online (Sandbox Code Playgroud)

来自man echo:

-n     do not output the trailing newline
-e     enable interpretation of backslash escapes

\r     carriage return
Run Code Online (Sandbox Code Playgroud)

  • `for i in {1..100000}; 做echo -en"\ r $ i"; 完成`以避免seq调用:-) (19认同)
  • 当你使用诸如"for i in $(...)"或"for i in {1..N}"之类的东西时,你会在迭代之前生成所有元素,这对于大输入来说效率非常低.您可以利用管道:"seq 1 100000 | while read i; do ..."或使用bash c-style for循环:"for((i = 0 ;; i ++)); do ..." (11认同)
  • 我的矩阵打印机完全弄乱了我的纸张。它不断地将点堵塞在同一张纸上,但该纸已不再存在,该程序运行多长时间? (2认同)

小智 17

只要线长不超过终端宽度,Derek Veit的答案就能很好地解决.如果不是这种情况,以下代码将阻止垃圾输出:

在第一次写行之前,做

tput sc
Run Code Online (Sandbox Code Playgroud)

它保存当前光标位置.现在,无论何时打印您的线路,请使用

tput rc
tput ed
echo "your stuff here"
Run Code Online (Sandbox Code Playgroud)

首先返回保存的光标位置,然后从光标到底部清除屏幕,最后写入输出.


lee*_*8oi 11

\ 033方法对我不起作用.\ r \n方法有效,但实际上并没有删除任何内容,只需将光标放在行的开头即可.因此,如果新字符串比旧字符串短,您可以在该行的末尾看到剩余的文本.最终,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
Run Code Online (Sandbox Code Playgroud)

这是一个可以玩的小倒计时脚本:

#!/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"
Run Code Online (Sandbox Code Playgroud)


Aki*_*kif 7

您可以通过放置回车来实现\r

在一行代码中printf

for i in {10..1}; do printf "Counting down: $i\r" && sleep 1; done
Run Code Online (Sandbox Code Playgroud)

或与echo -ne

for i in {10..1}; do echo -ne "Counting down: $i\r" && sleep 1; done
Run Code Online (Sandbox Code Playgroud)


Dar*_*man 6

如果您只想清除前一行,下面的代码可能会成功。

printf '\033[1A\033[K'
Run Code Online (Sandbox Code Playgroud)

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

for i in {1..10}; do
    printf '\033[1A\033[K'
done
Run Code Online (Sandbox Code Playgroud)

这将清除最后 10 行。


Mik*_*l S 5

使用回车符:

echo -e "Foo\rBar" # Will print "Bar"
Run Code Online (Sandbox Code Playgroud)


Mr.*_*ito 5

如果进度输出是多行,或者脚本已经打印了新行字符,则可以使用以下内容向上跳行:

printf "\033[5A"

这会使光标向上跳5行。然后,您可以覆盖所需的任何内容。

如果那行不通,您可以尝试printf "\e[5A"echo -e "\033[5A",它应该具有相同的效果。

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