在 Python 中为当前进程设置终端宽度
Set terminal width in Python for the current process
我想在 Python 中使用 \r
做一个控制台进度条来清除显示。为了支持多行进度条(用于多个并行任务),我想知道是否可以为当前进程设置终端宽度,以便长行可以换行?
例如,如果我将终端宽度设置为 20
,我可以这样设置进度条:
print '\r%-20s%-20s' % ('Task 1: 30%', 'Task 2: 60%'),
time.sleep(1)
print '\r%-20s%-20s' % ('Task 1: 35%', 'Task 2: 65%'),
我知道可以使用 ncurses
(或使用 ncurses
的进度条包),我只是想知道是否有不使用 ncurses
的解决方案。
我已经从 尝试了 set_winsize
,但它没有用,线仍然没有换行。
谢谢!
使用指定的方法更改终端宽度(rxvt 从 xterm 中获得的功能 based on a feature from dtterm)may/may 不起作用,具体取决于您使用的实际终端。但是还有更直接的方法。
与其写一长串希望终端将其换行,不如
- 写一个转义序列将光标移动到左上角,
- 写下你的进度条(用转义序列清除每一行的剩余部分),并明确地包装它们,并且
- 写一个转义序列以清除之前的屏幕剩余部分
- 稍等片刻再重复该过程
这是一个例子:
import curses, time, sys
def go_to_top_left():
curses.putp(curses.tparm(curses.tigetstr("cup"),0,0))
def show_bar(n):
curses.putp(curses.tigetstr("rev"))
sys.stdout.write('.' * n)
sys.stdout.write('*')
curses.putp(curses.tigetstr("sgr0"))
curses.putp(curses.tigetstr("el"))
sys.stdout.write('\n')
sys.stdout.flush()
def clear_to_bottom():
curses.putp(curses.tigetstr("ed"))
def progress_bars():
curses.setupterm()
foo = 1
bar = 0
while foo < 50:
go_to_top_left()
show_bar(foo)
show_bar(bar)
bar = foo
foo = foo + 1
clear_to_bottom()
time.sleep(1)
progress_bars()
该示例使用来自 curses 包的 terminfo 调用。与 termcap 一样,这些调用不会 优化 光标的移动,并且您可以控制实际清除屏幕的时间。如果你想完全放弃清算,你必须做出几个关于
的假设
- 进度条的宽度,
- 屏幕上已有内容,并且
- 您在屏幕上的哪个位置执行此操作。
(有人可能会提供与此示例等效的硬编码 "improvement")。
延伸阅读:
- Types of library users(ncurses 常见问题解答)
与其尝试设置终端宽度,不如适应终端大小的变化。
这个小程序就是这样做的。
运行 它并调整终端的大小;观察输出调整大小。
我从 this elaborate example 中获取了 IOCTL 代码。
import fcntl
import signal
import struct
import sys
import termios
import time
def ioctl_GWINSZ(fd): #### TABULATION FUNCTIONS
return struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234'))
def draw_line(width, left_cap, body, right_cap):
w = sys.stdout.write
w(left_cap)
w(body * (width - 2))
w(right_cap)
def draw_rect(width, height):
draw_line(width, '/', '-', '\')
for n in xrange(height - 3):
draw_line(width, '|', ' ', '|')
draw_line(width, '\', '-', '/')
def draw_screen():
h, w = ioctl_GWINSZ(1) # of stdout.
draw_rect(w, h)
sys.stdout.write('Rows: %3d, Cols: %3d' % (h, w))
sys.stdout.flush()
def on_winch(*ignored):
sys.stdout.write('\n')
draw_screen()
if __name__ == '__main__':
draw_screen()
signal.signal(signal.SIGWINCH, on_winch)
while True:
time.sleep(0.1)
我想在 Python 中使用 \r
做一个控制台进度条来清除显示。为了支持多行进度条(用于多个并行任务),我想知道是否可以为当前进程设置终端宽度,以便长行可以换行?
例如,如果我将终端宽度设置为 20
,我可以这样设置进度条:
print '\r%-20s%-20s' % ('Task 1: 30%', 'Task 2: 60%'),
time.sleep(1)
print '\r%-20s%-20s' % ('Task 1: 35%', 'Task 2: 65%'),
我知道可以使用 ncurses
(或使用 ncurses
的进度条包),我只是想知道是否有不使用 ncurses
的解决方案。
我已经从 尝试了 set_winsize
,但它没有用,线仍然没有换行。
谢谢!
使用指定的方法更改终端宽度(rxvt 从 xterm 中获得的功能 based on a feature from dtterm)may/may 不起作用,具体取决于您使用的实际终端。但是还有更直接的方法。
与其写一长串希望终端将其换行,不如
- 写一个转义序列将光标移动到左上角,
- 写下你的进度条(用转义序列清除每一行的剩余部分),并明确地包装它们,并且
- 写一个转义序列以清除之前的屏幕剩余部分
- 稍等片刻再重复该过程
这是一个例子:
import curses, time, sys
def go_to_top_left():
curses.putp(curses.tparm(curses.tigetstr("cup"),0,0))
def show_bar(n):
curses.putp(curses.tigetstr("rev"))
sys.stdout.write('.' * n)
sys.stdout.write('*')
curses.putp(curses.tigetstr("sgr0"))
curses.putp(curses.tigetstr("el"))
sys.stdout.write('\n')
sys.stdout.flush()
def clear_to_bottom():
curses.putp(curses.tigetstr("ed"))
def progress_bars():
curses.setupterm()
foo = 1
bar = 0
while foo < 50:
go_to_top_left()
show_bar(foo)
show_bar(bar)
bar = foo
foo = foo + 1
clear_to_bottom()
time.sleep(1)
progress_bars()
该示例使用来自 curses 包的 terminfo 调用。与 termcap 一样,这些调用不会 优化 光标的移动,并且您可以控制实际清除屏幕的时间。如果你想完全放弃清算,你必须做出几个关于
的假设- 进度条的宽度,
- 屏幕上已有内容,并且
- 您在屏幕上的哪个位置执行此操作。
(有人可能会提供与此示例等效的硬编码 "improvement")。
延伸阅读:
- Types of library users(ncurses 常见问题解答)
与其尝试设置终端宽度,不如适应终端大小的变化。
这个小程序就是这样做的。 运行 它并调整终端的大小;观察输出调整大小。
我从 this elaborate example 中获取了 IOCTL 代码。
import fcntl
import signal
import struct
import sys
import termios
import time
def ioctl_GWINSZ(fd): #### TABULATION FUNCTIONS
return struct.unpack('hh', fcntl.ioctl(fd, termios.TIOCGWINSZ, '1234'))
def draw_line(width, left_cap, body, right_cap):
w = sys.stdout.write
w(left_cap)
w(body * (width - 2))
w(right_cap)
def draw_rect(width, height):
draw_line(width, '/', '-', '\')
for n in xrange(height - 3):
draw_line(width, '|', ' ', '|')
draw_line(width, '\', '-', '/')
def draw_screen():
h, w = ioctl_GWINSZ(1) # of stdout.
draw_rect(w, h)
sys.stdout.write('Rows: %3d, Cols: %3d' % (h, w))
sys.stdout.flush()
def on_winch(*ignored):
sys.stdout.write('\n')
draw_screen()
if __name__ == '__main__':
draw_screen()
signal.signal(signal.SIGWINCH, on_winch)
while True:
time.sleep(0.1)