【问题标题】:Out of order output from PopenPopen 的乱序输出
【发布时间】:2013-08-08 17:47:16
【问题描述】:

我正在编写一个替代终端窗口(使用 PySide),我正在使用以下命令运行 shell (bash):

subprocess.Popen(['/bin/bash','-i'],....

同时将各种 stdio 设置为 subprocess.PIPE
我还使用

禁用了输出 stdio (out,err) 的缓冲
fcntl(s.fileno(),F_SETFL,os.O_NONBLOCK)

然后我使用计时器来轮询输出 io 以获取可用数据并拉取它。

它工作得很好,但有时我会遇到一些奇怪的行为。如果在提示符下我发出命令(例如 pwd),我会得到两个不同的可能输出:

/etc:$ pwd
/etc
/etc:$ 

另一个是

/etc:$ pwd/etc

/etc:$

就好像命令中的换行符和输出的其余部分被交换了一样。基本上任何命令都会发生这种情况,例如,对于 ls,第一个文件出现在 ls 之后,最后一个文件之后出现一个空行。
让我烦恼的是它并不一致。

编辑:添加完整代码示例

#!/usr/bin/python
from PySide import QtCore
from PySide import QtGui
import fcntl
import os
import subprocess
import sys

class MyTerminal(QtGui.QDialog):
    def __init__(self,parent=None):
        super(MyTerminal,self).__init__(parent)
        startPath=os.path.expanduser('~')
        self.process=subprocess.Popen(['/bin/bash','-i'],cwd=startPath,stdout=subprocess.PIPE,stdin=subprocess.PIPE,stderr=subprocess.PIPE)
        fcntl.fcntl(self.process.stdout.fileno(),fcntl.F_SETFL,os.O_NONBLOCK)
        fcntl.fcntl(self.process.stderr.fileno(),fcntl.F_SETFL,os.O_NONBLOCK)
        self.timer=QtCore.QTimer(self)
        self.connect(self.timer,QtCore.SIGNAL("timeout()"),self.onTimer)
        self.started=False

    def keyPressEvent(self,event):
        text=event.text()
        if len(text)>0:
            if not self.started:
                self.timer.start(10)
                self.started=True
            self.sendKeys(text)
            event.accept()

    def sendKeys(self,text):
        self.process.stdin.write(text)

    def output(self,text):
        sys.stdout.write(text)
        sys.stdout.flush()

    def readOutput(self,io):
        try:
            text=io.read()
            if len(text)>0:
                self.output(text)
        except IOError:
            pass

    def onTimer(self):
        self.readOutput(self.process.stdout)
        self.readOutput(self.process.stderr)

def main():
    app=QtGui.QApplication(sys.argv)
    t=MyTerminal()
    t.show()
    app.exec_()


if __name__=='__main__':
    main()

【问题讨论】:

  • 如果您希望我们能够提供帮助,您将不得不提供超过 0.5 行代码。
  • 您当然是对的,魔鬼在代码细节中。我试图创建一个显示问题的小代码示例,在这样做的同时,发现问题可能在于 stdout 和 stderr 之间的同步。我正在调查。

标签: python shell pipe stdio


【解决方案1】:

在尝试创建要粘贴的小代码示例(在上面添加)之后,我注意到问题是由于 stdout 和 stderr 之间的同步而出现的。
一点点搜索让我想到了以下问题:
Merging a Python script's subprocess' stdout and stderr while keeping them distinguishable

我在那里尝试了第一个答案并使用了轮询方法,但这并没有解决问题,因为我正在以与以前相同的方式混合事件。
解决问题的是 mossman 的回答,它基本上将 stderr 重定向到了 stdout,在我的情况下这已经足够了。

【讨论】:

    猜你喜欢
    • 2018-01-10
    • 2012-03-09
    • 2020-04-30
    • 1970-01-01
    • 2018-06-16
    • 2014-03-04
    • 2013-05-20
    • 2015-09-21
    • 2019-01-25
    相关资源
    最近更新 更多