I'm looking for a python module that provides a TRUE interactive os shell (in Linux, win, & mac os) via the STDIO. I've tried various examples using subprocess+PIPES and/or QProcess to start csh/bash or cmd.exe and then provide a crude terminal IO via QTextEdit keyPressEvents. This works ok for basic os commands but if I want to start another app within the shell process (ex. telnet, ssh, tcl, python, netstat, etc., etc.) stdin and stdout are no longer attached, probably due to a new child process being created. Will I have to subprocess/QProcess each command and keep track of all the child processes? -- that's going to be ugly, there has to be a better way... (I have also looked at pexpect/wexpect but couldn't get it working reliably.)
Environment: Win7, RHEL6.4, Python 2.7.8, Qt 4.8.6
It seems like the requested module would be part of a standard PyQt library; am I missing something? Perhaps there's not much of a need for a true interactive os shell within python.
Sample snippet of crude shell terminal:
class Console(QtGui.QTextEdit):
def __init__(self, startup_message='', parent=None):
super(Console, self).__init__(parent)
. . .
# TextEdit settings
self.setAcceptRichText(True)
#QProcess setup
self.proc = QtCore.QProcess()
self.proc.setProcessChannelMode(QtCore.QProcess.MergedChannels)
self.proc.setReadChannelMode(QtCore.QProcess.MergedChannels)
QtCore.QObject.connect(self.proc, QtCore.SIGNAL("readyReadStandardOutput()"), self.procReadStdOutput)
. . .
if sys.platform == "win32":
self.proc.start(r"cmd.exe", mode=QtCore.QProcess.ReadWrite)
elif sys.platform == "linux2":
self.proc.start(r"csh", mode=QtCore.QProcess.ReadWrite)
. . .
def runCommand(self):
if self.userTextEntry != "":
self.userCommand = self.userTextEntry
self.userTextEntry = ""
try:
self.proc.writeData(self.userCommand)
except Exception as error:
self.append(str(error))
else:
self.append(self.prompt)
return
. . .
def keyPressEvent(self, event):
if event.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return):
event.accept()
self.userTextEntry += "\n"
self.runCommand()
. . .
@QtCore.pyqtSlot()
def procReadStdOutput(self):
self.append(QtCore.QString(self.proc.readAllStandardOutput()))
self.append(self.getOSPrompt())
self.proc.emit(QtCore.SIGNAL("cmdDone()"))
return