覆盖终端上的最后一行

时间:2012-07-01 16:18:09

标签: bash terminal escaping

我的bash-script看起来如下:

echo "Description:"
while [ $finishInput -eq 0 ]; do
read tmp
desc="$desc"$'\n'"$tmp"
if [ -z "$tmp" ]; then
finishInput="1"
fi
done
echo -n "Maintainer:"
read maintainer

它读取desc var直到传递空行。在那之后,我想阅读其他内容。

执行当前脚本时,它看起来像这样:

Description:
Line 1
Line 2

Maintainer:

我想用“Maintainer:”覆盖最后一个空行。

我搜索了一个解决方案,但只找到了像

这样的建议
echo -n "Old line"
echo -e "\r new line"

保留在线上并覆盖它。在我的情况下,这是不可能的。

6 个答案:

答案 0 :(得分:67)

只需使用"\e[1A"

在您的示例中,您删除同一行的文本:

$ echo -n "Old line"; echo -e "\e[0K\r new line"
 new line

如果要返回上一行,请使用\ e [1A:

$ echo "Old line"; echo -en "\e[1A"; echo -e "\e[0K\r new line"
 new line

当你想要N行时,请使用\e[<N>A

答案 1 :(得分:12)

我从Dennis Williamsons Comment构建了一个函数:

function clearLastLine() {
        tput cuu 1 && tput el
}

感谢Dennis Williamson

答案 2 :(得分:11)

找到了一个不错的guide on escape sequences,并希望在这里展开一些讨论。

当您写出一个终端时,您将移动一个不可见的光标,就像在任何文本编辑器中编写时一样。使用echo时,它将以换行符自动结束输出,该字符将光标移至下一行。

$ echo "Hello" && echo " World"
Hello
 World

您可以使用-n阻止新行,如果在此之后再次回显,它将添加到该行的末尾

$ echo -n "Hello" && echo " World"
Hello World

光标本身保持原样,我们不能使用-n覆盖上一行,我们需要将光标向左移动。为此,我们需要给它一个转义序列,让echo知道我们将与-e一起使用,然后通过提供一个返回回车\r来移动光标,光标放在行首。

$ echo -n "Hello" && echo -e "\rWorld"
World

这看起来像是可行的,但是看看会发生什么

$ echo -n "A longer sentance" && echo -e "\rShort sentance"
Short sentancence

看到多余的字符了吗?简单地在行上书写只会更改我们编写它们的字符。

要解决此问题,上面接受的答案使用转义符\e[0K来删除光标向左移动之后光标之后的所有内容。即\r移至开头\e[0K擦除至结束。

$ echo -n "A longer sentance" && echo -e "\r\e[0KShort sentance"
Short sentance

重要 \ezsh中有效,但在sh中无效,并且不一定在bash中有效,但是{{1} }对所有这些都有效。如果您希望脚本在任何地方都可以使用,则应首选\033

\033

但是转义字符可以提供更多实用性。例如$ echo -n "A longer sentance" && echo -e "\r\033[0KShort sentance" Short sentance 将光标移动到上一行,因此我们不需要上一个回显上的\033[1A

-n

$ echo "A longer sentance" && echo -e "\r\033[1A\033[0KShort sentance" Short sentance 移至开头\r移至\033[1A末尾

最后,这在我的书中有点混乱,因此您可以将其变成一个函数:

\033[0K

使用overwrite() { echo -e "\r\033[1A\033[0K$@"; } 只是将函数的所有参数放入字符串中

$@

希望能帮助想了解更多信息的人。

答案 3 :(得分:5)

如果您在没有换行符echo -n "Something"的情况下回音,则可以使用\r与下一个回音移动&#39; 光标&#39;到行echo -e "\\rOverwrite something"的开头。

bash overwrite terminal line

#!/bin/bash

CHECK_MARK="\033[0;32m\xE2\x9C\x94\033[0m"

echo -e "\n\e[4mDoing Things\e[0m"
echo -n "doing thing 1..."
sleep 1
echo -e "\\r${CHECK_MARK} thing 1 done"

请注意,如果您的新字符串比旧字符串短,则旧字符串的尾部仍然可见。请注意上面gif中的done..

答案 4 :(得分:1)

#!/bin/bash

echo "Description:"
while test -z $finishInput; do
 read -s tmp
 desc="$desc"$'\n'"$tmp"
 if [ -z "$tmp" ]; then
 finishInput=1
 else
    echo $tmp
 fi
 #echo "fi="$finishInput;
done
echo -n "Maintainer:"
read maintainer

此解决方案避免空行,但在行完成之前不会回显输入。

提示:我的bash版本不接受“[$ finishInput -eq 0]”。

答案 5 :(得分:0)

如果您想循环运行脚本而又不破坏回滚,则可以使用以下模式:

while sleep 10s; do 
  echo -n $(script)
  echo -n -e "\e[0K\r"
done

只需将script命令替换为您自己的命令即可。