You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Linux terminal emulator中清除多行并实现多progressbar可视化?

嘿,这两个问题我刚好折腾过,给你详细拆解一下~

一、在Linux终端模拟器中清除最后多行内容

其实不用依赖复杂工具,靠终端支持的ANSI转义序列就能轻松搞定,这也是终端程序控制光标和内容的常用手段。

比如要清除最后两行,步骤很简单:

  1. 先把光标向上移动2行,用转义序列 \e[2A(\e是转义字符的简写,也可以写成\033)
  2. 然后清除从当前光标位置到屏幕末尾的所有内容,用 \e[J

给你整个bash脚本示例,直观看看效果:

# 先输出两行测试内容
echo "第一行测试文本"
echo "第二行测试文本"
sleep 2  # 暂停2秒让你看清内容
# 光标上移2行,再清除下方所有内容
echo -e "\e[2A\e[J"

如果要清除更多行,把2A里的数字改成对应的行数就行,比如清除5行就是\e[5A\e[J。

要是你不想完全清除,只是想覆盖这些行的内容,也可以移动光标后配合\e[K(清除当前行光标到行尾的内容)来更新,比如:

echo "旧内容行1"
echo "旧内容行2"
sleep 2
echo -e "\e[2A"  # 回到第一行开头
echo "新内容行1\e[K"  # 输出新内容并清掉行尾多余字符
echo "新内容行2\e[K"  # 自动换行到第二行,更新内容
二、实现多行任务进度条(不用ncurses的轻量方案)

单进度条用回车\r覆盖单行确实简单,但多行的话核心思路还是靠ANSI转义序列控制光标,逐行重绘进度条——不用ncurses完全能搞定,轻量又灵活。

先给你说几个核心的转义序列:

  • \e[nA:光标向上移动n行
  • \e[nB:光标向下移动n行
  • \e[K:清除当前行从光标到行尾的内容
  • \e[nG:把光标定位到当前行的第n列(可选,用来对齐进度条)

我用Python写了个简单示例,模拟3个下载任务的进度更新,你可以直接跑起来看效果:

import time
import sys

def update_progress(prog_list):
    # 把光标移到最上面的进度条行(因为一开始输出了3行占位)
    sys.stdout.write(f"\e[{len(prog_list)}A")
    for idx, prog in enumerate(prog_list):
        # 进度条长度设为20,计算已填充的长度
        bar_total = 20
        filled = int(bar_total * prog / 100)
        bar = '█' * filled + '-' * (bar_total - filled)
        # 输出进度条+百分比,清掉行尾多余内容
        sys.stdout.write(f"任务{idx+1}: [{bar}] {prog}%\n\e[K")
    sys.stdout.flush()  # 必须刷新缓冲区,不然内容不会立刻显示

# 初始化3个任务的进度
progress = [0, 0, 0]
# 先输出3行空占位,让光标停在进度条下方
for _ in progress:
    print("")

# 模拟进度更新
while max(progress) < 100:
    # 随机给每个任务涨进度
    for i in range(len(progress)):
        if progress[i] < 100:
            progress[i] += 1
    update_progress(progress)
    time.sleep(0.1)

# 最后清除进度条区域,输出完成提示
sys.stdout.write(f"\e[{len(progress)}A\e[J")
print("所有任务都完成啦!")

这个脚本的逻辑是:先输出和任务数一样多的空行占位,每次更新进度时,把光标拉回最上面的进度行,逐行重新输出每个任务的进度条,然后刷新输出缓冲区——这样看起来就是每行的进度条在实时更新。

要是你用bash脚本实现,思路完全一样,只是语法不同,给你个bash版本的示例:

#!/bin/bash

# 任务数量
TASK_COUNT=3
# 初始化每个任务的进度
progress=(0 0 0)

# 先输出占位行
for ((i=0; i<TASK_COUNT; i++)); do
    echo ""
done

# 模拟进度更新循环
while true; do
    # 把光标移到第一个进度行
    echo -ne "\e[${TASK_COUNT}A"
    all_finished=1
    for ((i=0; i<TASK_COUNT; i++)); do
        if [[ ${progress[$i]} -lt 100 ]]; then
            progress[$i]=$((progress[$i]+1))
            all_finished=0
        fi
        # 绘制进度条
        bar_length=20
        filled=$((bar_length * progress[$i] / 100))
        bar=$(printf "%${filled}s" "" | tr ' ' '█')
        bar+=$(printf "%$((bar_length - filled))s" "" | tr ' ' '-')
        echo -ne "任务$((i+1)): [${bar}] ${progress[$i]}%\n\e[K"
    done
    # 光标移回下方(可选,不影响进度更新)
    echo -ne "\e[${TASK_COUNT}B"
    # 所有任务完成就退出循环
    [[ $all_finished -eq 1 ]] && break
    sleep 0.1
done

# 清除进度条区域,输出完成提示
echo -ne "\e[${TASK_COUNT}A\e[J"
echo "所有任务完成!"

为啥不用ncurses?确实ncurses是专门做终端UI的,功能强大,但如果只是做个简单的多行进度条,用ANSI转义序列足够轻量,不需要额外安装依赖——而且现在主流的终端模拟器(比如gnome-terminal、konsole、iTerm2)都完美支持这些转义序列,兼容性没问题。

内容的提问来源于stack exchange,提问作者Martin Jiřička

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:47:16