Bash脚本,删除前一行?

27
在许多Linux程序中,比如curl、wget以及任何带有进度条的程序,它们会每隔一定时间更新底部行。我该如何在bash脚本中实现这个功能?目前我只能使用echo换行,但这并不是我想要的,因为会积累起来。我曾经看到过一个提到"tput cup 0 0"的方法,但我尝试了一下,发现有点怪异。有没有更好的方法呢?

我认为这可以使用ncurses完成,但也许有更好的方法 - 我也很想知道。 - naumcho
1
阅读答案后,我得到的要点是 '\r' 可以将光标回到行首。因此,只需使用不带换行符 [-n] 的 echo 命令,然后 echo -ne '\r' 就可以回到行首了。 - Matt
接受的答案未能回答问题。 - Thomas Dickey
6个回答

45
{
  for pc in $(seq 1 100); do
    echo -ne "$pc%\033[0K\r"
    usleep 100000
  done
  echo
}

"\033[0K"将删除到行尾-以防止进度行在某些时候变短,尽管这可能对你的目的并非必要。

"\r"将把光标移到当前行的开头

echo命令中的-n选项将防止光标向下一行移动


太棒了!非常好的小例子。 - naumcho

19

您也可以使用tput cuu1; tput el(或printf '\e[A\e[K')将光标向上移动一行并擦除该行:

for i in {1..100};do echo $i;sleep 1;tput cuu1;tput el;done

1
那个 printf '\e[A\e[K' 是唯一一个真正解决我的问题的方法!感谢分享! - João Ciocca

13

在linuts的代码示例上进行小变动,将光标移动到当前行的末尾而不是开头。

{
  for pc in {1..100}; do
    #echo -ne "$pc%\033[0K\r"
    echo -ne "\r\033[0K${pc}%"
    sleep 1
  done
  echo
}

8
通常使用printf '\r'来实现。在这种情况下,没有必要进行光标定位。

8

要实际删除之前的行,而不仅仅是当前行,您可以使用以下bash函数:

# Clears the entire current line regardless of terminal size.
# See the magic by running:
# { sleep 1; clear_this_line ; }&
clear_this_line(){
        printf '\r'
        cols="$(tput cols)"
        for i in $(seq "$cols"); do
                printf ' '
        done
        printf '\r'
}

# Erases the amount of lines specified.
# Usage: erase_lines [AMOUNT]
# See the magic by running:
# { sleep 1; erase_lines 2; }&
erase_lines(){
        # Default line count to 1.
        test -z "$1" && lines="1" || lines="$1"

        # This is what we use to move the cursor to previous lines.
        UP='\033[1A'

        # Exit if erase count is zero.
        [ "$lines" = 0 ] && return

        # Erase.
        if [ "$lines" = 1 ]; then
                clear_this_line
        else
                lines=$((lines-1))
                clear_this_line
                for i in $(seq "$lines"); do
                        printf "$UP"
                        clear_this_line
                done
        fi
}

现在,只需调用erase_lines 5来清除终端中的最后5行即可。

这个翻译更接近了,但忽略了显示屏上可能比要求的行数少的可能性。 - Thomas Dickey

0

查看 man terminfo(5) 并查看 "cap-nam" 列。

clr_eol=$(tput el)
while true
do
    printf "${clr_eol}your message here\r"
    sleep 60
done

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接