如何在python中使用pexpect获得子进程的自发输出

2024-09-24 22:33:10 发布

您现在位置:Python中文网/ 问答频道 /正文

这与我的另一篇文章multithreading issue with wx.TextCtrl (or underlying GTK+)有关,在更正了从主线程调用GUI交互之后,我发现它再次出现了管道块缓冲问题。那么如何从subprocess.stdout获得自发输出呢?

简而言之,目前我正在使用subprocess.popen启动一个外部的长时间运行程序。

    launchcmd=["EXTERNAL_PROGRAM_EXE"]
    p = subprocess.Popen(launchcmd, stdin=subprocess.PIPE, 
            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    self.outputThread = BashProcessThread(p.stdout.readline)
    self.outputThread.start()
    # wx.TextCtrl is used to make input/output
    self.textctrl = wx.TextCtrl(self, style=wx.TE_PROCESS_ENTER|wx.TE_MULTILINE)

我用一个单独的线程来读取后台程序的stdout,用“wx.CallAfter”来回拨。

class BashProcessThread(threading.Thread):
    def __init__(self, readlineFunc, textctrl):
        threading.Thread.__init__(self)
        self.readlineFunc = readlineFunc

    def run(self):
        while True:
           line = self.readlineFunc()
           wx.CallAfter(textctrl.appendText(line))

上面的代码打印出子流程日志消息块挂起块(而不是自发的逐行打印),最糟糕的是剩下的5-6行日志消息无法及时打印,直到用户发送下一个输入。

从我以前的文章中,我了解到有pty和pexpect,这可能使子流程认为它与伪tty交互。但是应该如何使用pexpect,特别是考虑到后台进程是长期的、独立运行的任务?

例如,如果我使用

child=pexpect.spawn(launchcmd)

如何获取子流程的输出和输入,以便可以使用wx.TextCtrl打印输出,还可以使用wx.TextCtrl将用户输入转发到子流程?


Tags: selfstdout文章流程pexpectsubprocesswxte
2条回答

我发现这两种方法对于获得实时输出效果很好。

如果不希望用户交互选项,例如在后台进程中:

child = pexpect.spawn(launchcmd)
child.logfile = sys.stdout
child.expect(pexpect.EOF)
child.close()

如果您不使用后台进程并希望能够与程序交互(如果它提示您)。这里发生的情况是进入交互模式,pexpect直接向屏幕写入数据。当程序命中时,它会抛出一个错误。

child = pexpect.spawn(launchcmd)
try:
    child.interact()
except OSError:
    pass
child.close()    

你有没有试过类似的方法:

child = pexpect.spawn(launchcmd)
while True:
    try:
        child.expect('\n')
        print(child.before)
    except pexpect.EOF:
        break

相关问题 更多 >