您可以使用
ANSI转义序列进行光标移动,其中最重要的是:
- 定位光标:
\033[<L>;<C>H
或\033[<L>;<C>f
将光标放在第L行和第C列。
- 向上移动光标N行:
\033[<N>A
- 向下移动光标N行:
\033[<N>B
- 向前移动光标N列:
\033[<N>C
- 向后移动光标N列:
\033[<N>D
- 保存光标位置:
\033[s
- 恢复光标位置:
\033[u
光标位置的保存/恢复似乎非常适合您的情况,但不幸的是,这两个代码并未被许多终端模拟器支持。
尽管在终端的最后一行/滚动输出时会出现问题(如@ThomasDickey在评论中指出),但它们可以在xterm
和xfce4-terminal
中运行。请尝试:
echo -e "\033[s" {1..100} "\033[u" "Overwrite"
对于其他终端仿真器,您可以尝试使用
\033[<N>A
将光标向上移动所需数量的行,然后移动到列
0
。
如果您知道您的行长度,您可以计算出它在换行时跨越了多少行(如果有)(例如
bash
示例,请注意使用
COLUMNS
环境变量)。
line='...'
len=${#line}
rows=$((len / COLUMNS))
然后使用以下代码向上移动:
printf "\033[%dA" "$rows"
在Python中,您可以像这样使用它:
print("\033[s", "123"*100, "\033[u", "Overwrite", sep='')
print("\033[%dA" % 3, "Overwrite", sep='')
或者,使用类似 curses
的东西来抽象所有这些内容。
Python解决方案
基于“将光标上移N行” ANSI 转义序列(在大多数终端模拟器中都可用),以及跨 Python 兼容的 终端宽度检测代码(在 Python3 中可以使用 shutil.get_terminal_size
),这是一个概念验证演示,适用于滚动输出,适应行长度和不断变化的终端宽度:
from __future__ import print_function
import os
import time
cnt = 0
while True:
with os.popen('stty size', 'r') as stty:
rows, columns = stty.read().split()
line = "Run: {}, Columns: {}, Filler: {}".format(cnt, columns, "***"*100)
print(line)
print("\033[{}A".format(len(line) // int(columns) + 1), end='')
time.sleep(1)
cnt += 1
sleep
,在 resize 过程中你采样到错误的终端尺寸的概率会增加。我认为 curses 也无法解决这个问题。但是终端 resize 并不应该那么频繁发生,另一方面,你为什么需要每毫秒更新一次进度呢? - randomir