85

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

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

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

Description:
Line 1
Line 2

Maintainer:

我想用“维护者:”覆盖最后一个空行。

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

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

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

4

6 回答 6

123

在您的示例中,您删除了同一行的文本。当您想返回上一行使用\e[1A并清除该行时,请使用\e[K

echo 'Old line'
echo -e '\e[1A\e[Knew line'

当你想N排队时,使用\e[<N>A

于 2012-07-01T16:24:06.693 回答
61

找到了一个很棒的[转义序列指南][1],并想在这里展开一些讨论。

当你写到终端时,你会移动一个不可见的光标,就像你在任何文本编辑器中写一样。使用时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

重要 \e的是开始转义序列适用于zsh但不适用sh且不一定适用于bash,但\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$@"; }

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

$ echo Longer sentance && overwrite Short sentence
Short sentence

希望对想了解更多的人有所帮助。[1]:https ://shiroyasha.svbtle.com/escape-sequences-a-quick-guide-1

于 2018-08-15T12:06:48.033 回答
19

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

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

感谢丹尼斯威廉姆森

于 2014-12-05T23:59:50.303 回答
15

如果您回显时没有换行符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"

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

于 2018-04-17T22:34:34.227 回答
2

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

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

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

于 2018-10-31T20:54:43.907 回答
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 ]”。

于 2012-07-01T16:47:46.923 回答