Python Pexpect 清除或刷新行

13

我试图在从未知状态中恢复后清除行上的任何字符,因为在某些情况下,它们会包含我将来在 expect 方法调用中使用的提示和其他关键字。我尝试了多种方法,但结果各异,因为我不断遇到非预期的行为。

发现了一些意外行为(使用带有 Python 2.7.9 的 pexpect V3.3):

  1. 在执行以下代码后,当我随后尝试从缓冲区读取时,偶尔会看到不稳定的行为,其中只清除了一部分累积字符。这会极大地影响我的下游逻辑。我认为这是因为整个线程被休眠了 5 秒钟,所以当它醒来时,在执行 read_nonblocking() 命令之前没有时间获取完整的传入缓冲区。

    time.sleep(5)
    flushedStuff += child.read_nonblocking(100000, timeout=0)
    
    当我尝试使用.expect调用以非阻塞方式清除行时,我发现在超时异常后,输入缓冲区并没有被清除。可以在child.before属性中按预期找到其内容,但它也将在下一个.expect方法调用期间被解析。所以这根本没有清除该行!我还注意到,read_nonblocking()不从本地缓冲区读取,而是直接通过操作系统从行中读取,因此它看不到这一点。
    try:
        child.expect("ZzqQJjSh_Impossible_String", timeout = 5)
    except pexpect.TIMEOUT:
        pass
    flushedStuff = child.before
    

所以,经过所有这些,我现在提供一种可靠的方法来清除该行,即扩展spawn类并添加一个方法,该方法执行以下操作...访问一个未文档化的属性:

class ExtendedSpawn(pexpect.spawn):
    def flushBuffer(delay)
        try:
            # Greedily read in all the incoming characters
            self.expect("ZzqQJjSh_Impossible_String", timeout = delay)
        except pexpect.TIMEOUT:
            pass
        # Clear local input buffer inside the spawn Class
        self.buffer = self.string_type()
        return self.before

以上的方法也可以用于非阻塞睡眠命令。

这似乎是一个过于复杂的方式来实现一些本应简单的事情,更不用说我在这上面浪费了几天时间。有没有更好的方法?

谢谢!

2个回答

6
清空pexpect缓冲区的最简单方法是连续读取,直到有数据可用。
flushedStuff = ''
while not child.expect(r'.+', timeout=0.1):
    flushedStuff += child.match.group(0)

我猜这相当于 child.expect(r'.*', timeout=some_value),如果我们不想保留内容,对吧? - Adrian Pop

6
要查看问题,您可以运行以下脚本。(一个shell脚本将会打印从1到10的数字,并在每个数字后间隔1秒。pexpect将等待2秒超时并打印出看到的数字。)
#!/usr/bin/env python
import pexpect
child = pexpect.spawn('/bin/sh -c "i=0; while [ $i -lt 10 ]:; do echo $((i=i+1)); sleep 1; done"')
while True:
    i=child.expect ([pexpect.TIMEOUT, pexpect.EOF], timeout=2)
    if i==0:
        print "before=%s" % child.before
    else:
        break

输出结果如下(我们还会得到之前读取的数字):
before='1\r\n2\r\n'
before='1\r\n2\r\n3\r\n4\r\n'
before='1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n'
before='1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n'
before='1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n10\r\n'

为了解决这个问题,可以在脚本中添加两行代码:
#!/usr/bin/env python
import pexpect
child = pexpect.spawn('/bin/sh -c "i=0; while [ $i -lt 10 ]:; do echo $((i=i+1)); sleep 1; done"')
while True:
    i=child.expect ([pexpect.TIMEOUT, pexpect.EOF], timeout=2)
    if i==0:
        print "before=%s" % repr(child.before)
        if child.before:
            child.expect (r'.+')
    else:
        break

输出结果将会如预期:

before='1\r\n2\r\n'
before='3\r\n4\r\n'
before='5\r\n6\r\n'
before='7\r\n8\r\n'
before='9\r\n10\r\n'

可能是Stack Overflow上最被低估的答案。这个解决了我的问题。谢谢! - Frak

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