覆盖终端上的最后一行

Zul*_*kis 52 bash terminal escaping

我的bash脚本如下所示:

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
Run Code Online (Sandbox Code Playgroud)

它读取到desc var直到传递空行.在那之后,我想读其他的东西.

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

Description:
Line 1
Line 2

Maintainer:
Run Code Online (Sandbox Code Playgroud)

我想用"Maintainer:"覆盖最后一个空行.

我搜索了一个解决方案,但只找到了类似的建议

echo -n "Old line"
echo -e "\r new line"
Run Code Online (Sandbox Code Playgroud)

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

Igo*_*bin 73

只是用"\e[1A".

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

$ echo -n "Old line"; echo -e "\e[0K\r new line"
 new line
Run Code Online (Sandbox Code Playgroud)

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

$ echo "Old line"; echo -en "\e[1A"; echo -e "\e[0K\r new line"
 new line
Run Code Online (Sandbox Code Playgroud)

如果你想要N行,请使用\e[<N>A.

  • @Zulakis:参见`man 5 terminfo`并使用`tput`而不是硬编码序列.`tput cuu1`上升一行,`tput cuu 4`上升4行,`tput el`清除到行尾.你可以将它们保存在变量中并减少重复调用`tput`的开销:`ceol = $(tput el)`以及后来`echo'foo\r $ {ceol} A"` (11认同)
  • 你也可以使用-n保持同一条线.如上所述,这在我的案例中是不可能的. (3认同)
  • 最好在`\ e [0K`之前使用`\ r``,否则你将向右擦拭然后向左移动,可能会在您和所在的地方之间留下垃圾.虽然它应该是一个空白行,但两者都不是绝对必要的. (2认同)
  • 只是谷歌`终端ansi序列`.结果之一:http://www.termsys.demon.co.uk/vtansi.htm (2认同)

Dan*_*elM 19

找到了关于逃逸序列的精彩指南,并希望在此处扩展一些讨论.

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

$ echo "Hello" && echo " World"
Hello
 World
Run Code Online (Sandbox Code Playgroud)

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

$ echo -n "Hello" && echo " World"
Hello World
Run Code Online (Sandbox Code Playgroud)

光标保持原样,就它本身而言,我们不能-n用来覆盖前一行,我们需要将光标移动到左边.要做到这一点,我们需要给它一个转义序列,我们echo知道我们将要使用它-e,然后通过提供一个返回滑块\r来移动光标,该滑块将光标放在行的开头.

$ echo -n "Hello" && echo -e "\rWorld"
World
Run Code Online (Sandbox Code Playgroud)

这可能看起来有效,但看看会发生什么

$ echo -n "A longer sentance" && echo -e "\rShort sentance"
Short sentancence
Run Code Online (Sandbox Code Playgroud)

看到额外的字符?简单地在线上书写只会改变我们编写它们的字符.

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

$ echo -n "A longer sentance" && echo -e "\r\e[0KShort sentance"
Short sentance
Run Code Online (Sandbox Code Playgroud)

重要的 \e是开始转义序列在zsh但不在其中sh并且不一定在其中bash,但是\033在所有这些序列中都起作用.如果您希望您的脚本可以在任何地方工作,您应该优先考虑\033

$ echo -n "A longer sentance" && echo -e "\r\033[0KShort sentance"
Short sentance
Run Code Online (Sandbox Code Playgroud)

但转义字符可以提供更多实用性.例如,\033[1A将光标移动到上一行,因此我们不需要-n上一个回显:

$ echo "A longer sentance" && echo -e "\r\033[1A\033[0KShort sentance"
Short sentance
Run Code Online (Sandbox Code Playgroud)

\r移动到开头\033[1A向上移动\033[0K擦除到最后

最后,我的书中有点乱,所以你可以把它变成一个函数:

overwrite() { echo -e "\r\033[1A\033[0K$@"; }
Run Code Online (Sandbox Code Playgroud)

使用$@just将函数的所有参数放入字符串中

$ echo Longer sentance && overwrite Short sentence
Short sentence
Run Code Online (Sandbox Code Playgroud)

希望能帮助想要了解更多的人.

  • 这显然是最好、最彻底的答案。谢谢! (4认同)
  • 优秀的细节。这应该是最重要的答案。 (2认同)

Mur*_*mel 13

我从Dennis Williamsons建立了一个函数评论:

function clearLastLine() {
        tput cuu 1 && tput el
}
Run Code Online (Sandbox Code Playgroud)

感谢Dennis Williamson

  • @Zim"cuu#"是"向上#sline"和"el" - >"Clear to line of line"的缩写,参见:[gnu.org - tput](https://www.gnu.org/software /termutils/manual/termutils-2.0/html_chapter/tput_1.html) (2认同)

Der*_*ike 8

如果在没有换行符的情况下回显echo -n "Something",则可以使用\r下一个回显将" 光标 " 移动到行的开头echo -e "\\rOverwrite something".

bash覆盖终端线

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

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