bash 覆盖终端上的最后一行

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11283625/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 22:21:34  来源:igfitidea点击:

Overwrite last line on terminal

bashterminalescaping

提问by Zulakis

My bash-script looks as following:

我的 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

It reads to the desc var until a empty line is passed. After that, i want to read in other stuff.

它读取 desc var,直到传递一个空行。在那之后,我想阅读其他东西。

When executing my current script it looks like this:

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

Description:
Line 1
Line 2

Maintainer:

I would like to overwrite the last empty line with the "Maintainer:".

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

I searched for a solution but only found suggestions which were like

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

echo -n "Old line"
echo -e "\r new line"

which stays on the line and overwrites it. This is not possible in my case.

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

回答by Igor Chubin

Just use "\e[1A".

只需使用"\e[1A".

In your example you delete the text at the same line:

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

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

When you want to return to the previous line use \e[1A:

当您想返回到上一行时,请使用 \e[1A:

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

When you want to go N lines up, use \e[<N>A.

当您想排 N 行时,请使用\e[<N>A.

回答by DanielM

Found a great guide on escape sequencesand wanted to expand on some of the discussions here.

找到了一个很好的转义序列指南,并希望扩展这里的一些讨论。

When you write out to a terminal, you move an invisible cursor around, much like you do when you write in any text editor. When using echo, it will automatically end the output with a new line character which moves the cursor to the next line.

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

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

You can use -nto prevent the new line and if you echo again after this, it will append it to the end of that line

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

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

The cursor remains where it was so, on it's own, we can't use -nto overwrite the previous line, we need to move the cursor to the left. To do that we need to give it an escape sequence, which we let echoknow we're going to use with -eand then move the cursor by providing a return carriage \rwhich puts the cursor at the beginning of the line.

光标保持原样,靠它自己,我们不能-n用来覆盖上一行,我们需要将光标向左移动。要做到这一点,我们需要给它一个转义序列,让我们echo知道我们将使用它-e,然后通过提供一个\r将光标放在行首的回车来移动光标。

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

That may look like it worked, but see what happens with

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

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

See the extra characters? Simply writing over the line only changes the characters where we wrote them.

看到额外的字符了吗?简单地写在行上只会改变我们写的字符。

To fix this, the accepted answer above uses the escape character \e[0Kto erase everything after the cursor, after the cursor has moved left. i.e. \rmove to beginning \e[0Kerase to end.

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

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

Important\eto begin escape sequences works in zshbut not in shand not necessarily in bash, however \033works in all of them. If you want your script to work anywhere, you should preference \033

重要的\e是开始转义序列适用于zsh但不适用,sh不一定适用于bash,但\033适用于所有这些。如果你想让你的脚本在任何地方工作,你应该优先\033

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

But escape characters can provide even more utility. For example \033[1Amoves the cursor to the previous line so we don't need the -non the previous echo:

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

$ echo "A longer sentance" && echo -e "\r3[1A3[0KShort sentance"
Short sentance

\rmove to the beginning \033[1Amove up \033[0Kerase to the end

\r移到开头\033[1A向上移\033[0K擦除到结尾

Finally, this is all a bit messy in my book, so you can turn this into a function:

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

overwrite() { echo -e "\r3[1A3[0K$@"; }

Using $@just puts all the parameters of the function into the string

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

$ echo Longer sentance && overwrite Short sentence
Short sentence

Hope that helps people who want to know a bit more.

希望对想多了解的人有所帮助。

回答by Murmel

I built a function from Dennis Williamsons Comment:

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

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

Thanks to Dennis Williamson

感谢丹尼斯威廉姆森

回答by Derek Soike

If you echo without the newline character echo -n "Something", you can use \rwith your next echo to move the 'cursor' to the beginning of the line echo -e "\\rOverwrite something".

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

bash overwrite terminal line

bash 覆盖终端线

#!/bin/bash

CHECK_MARK="3[0;32m\xE2\x9C\x943[0m"

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

Just be aware that if your new string is shorter that your old string, the tail of your old string will still be visible. Note the done..in the gif above.

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

回答by Michael Besteck

#!/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

This solution avoids the empty line, but input is not echoed before the lines are complete.

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

Hint: My version of bash did not accept "[ $finishInput -eq 0 ]".

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

回答by maxywb

If you want to run a script in a loop and not blow up your scrollback, you can use the following pattern:

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

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

Just replace the scriptcommand with your own.

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