我试图让用户使用raw_input()在控制台上输入命令,这很好。问题是我有一些后台线程,偶尔将日志信息输出到屏幕上,并且当他们这样做时,它们会弄乱输入提示(因为输出到当前光标所在的位置)。
这是一个小的Python程序,它说明了我的意思。
#!/usr/bin/env python import threading import time def message_loop(): while True: time.sleep(1) print "Hello World" thread = threading.Thread(target = message_loop) thread.start() while True: input = raw_input("Prompt> ") print "You typed", input
这是运行时的外观示例:
Prompt> Hello World Hello World Hello World Hello World test You typed test Prompt> Hello World Hello World Hello World hellHello World o You typed hello Prompt> Hello World Hello World Hello World Hello World
我想要的是提示与线程的输出一起移动。像这样:
Hello World Hello World Prompt> test You typed test Hello World Hello World Hello World Hello World Hello World Prompt> hello You typed hello Hello World Hello World Hello World Hello World Prompt>
关于如何在不使用丑陋的黑客手段的情况下实现这一目标的任何想法?:)
我最近遇到了这个问题,并希望将此解决方案留在这里以备将来参考。这些解决方案从终端清除待处理的raw_input(readline)文本,打印新文本,然后将raw_input缓冲区中的内容重新打印到终端。
第一个程序非常简单,但是仅在只有一行文本等待raw_input时才能正确运行:
#!/usr/bin/python import time,readline,thread,sys def noisy_thread(): while True: time.sleep(3) sys.stdout.write('\r'+' '*(len(readline.get_line_buffer())+2)+'\r') print 'Interrupting text!' sys.stdout.write('> ' + readline.get_line_buffer()) sys.stdout.flush() thread.start_new_thread(noisy_thread, ()) while True: s = raw_input('> ')
输出:
$ ./threads_input.py Interrupting text! Interrupting text! Interrupting text! > WELL, PRINCE, Genoa and Lucca are now no more than private estates of the Bo Interrupting text! > WELL, PRINCE, Genoa and Lucca are now no more than private estates of the Bo naparte family. No, I warn you, that if you do not tell me we are at war,
第二个可以正确处理2条或更多的缓冲行,但是具有更多(标准)模块依赖性,并且需要一点点终端黑客:
#!/usr/bin/python import time,readline,thread import sys,struct,fcntl,termios def blank_current_readline(): # Next line said to be reasonably portable for various Unixes (rows,cols) = struct.unpack('hh', fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ,'1234')) text_len = len(readline.get_line_buffer())+2 # ANSI escape sequences (All VT100 except ESC[0G) sys.stdout.write('\x1b[2K') # Clear current line sys.stdout.write('\x1b[1A\x1b[2K'*(text_len/cols)) # Move cursor up and clear line sys.stdout.write('\x1b[0G') # Move to start of line def noisy_thread(): while True: time.sleep(3) blank_current_readline() print 'Interrupting text!' sys.stdout.write('> ' + readline.get_line_buffer()) sys.stdout.flush() # Needed or text doesn't show until a key is pressed if __name__ == '__main__': thread.start_new_thread(noisy_thread, ()) while True: s = raw_input('> ')
输出。先前的readline行已正确清除:
$ ./threads_input2.py Interrupting text! Interrupting text! Interrupting text! Interrupting text! > WELL, PRINCE, Genoa and Lucca are now no more than private estates of the Bo naparte family. No, I warn you, that if you do not tell me we are at war,