在[本帖][1]有一个类似的问题。
我想发送一个命令到我的子进程,解释响应,然后发送另一个命令。这似乎是一个耻辱,不得不启动一个新的子进程来完成这一点,特别是如果subprocess2必须执行许多与subprocess1相同的任务(例如ssh,打开mysql)。
我试了如下:
subprocess1.stdin.write([my commands])
subprocess1.stdin.flush()
subprocess1.stout.read()
但是如果没有read()
的字节数的明确参数,程序执行该指令时会卡住,并且我无法为read()
提供参数,因为我无法猜测流中有多少字节可用。
我正在运行WinXP, Py2.7.1
编辑
感谢@regularfry为我的真实意图提供了最佳解决方案(阅读他的回复中的评论,因为它们与通过SSH隧道实现我的目标有关)。(他/她的答案已被投票通过。)然而,为了那些以后想知道标题问题答案的观众的利益,我已经接受了@Mike Penningtion的答案。
您的选择是:
- 使用面向行的协议(并且使用readline()而不是read()),并确保发送的每个可能的行都是有效的消息;
- 使用read(1)和解析器来告诉你何时读取了完整的消息;或
- 将消息对象从子进程Pickle到流中,然后在父进程中取消Pickle。这将为您处理消息长度问题。
@JellicleCat,我正在跟进评论。我相信期待是圣人的一部分……据我所知,它不是单独打包的,但是你可以在这里下载wexpect。
老实说,如果您要驱动编程ssh会话,请使用paramiko。它被支持作为一个独立的安装,有良好的包装,并且应该本地安装在windows上。
编辑
示例paramiko脚本cd到一个目录,执行ls
命令并退出…捕获所有结果…
import sys
sys.stderr = open('/dev/null') # Silence silly warnings from paramiko
import paramiko as pm
sys.stderr = sys.__stderr__
import os
class AllowAllKeys(pm.MissingHostKeyPolicy):
def missing_host_key(self, client, hostname, key):
return
HOST = '127.0.0.1'
USER = ''
PASSWORD = ''
client = pm.SSHClient()
client.load_system_host_keys()
client.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
client.set_missing_host_key_policy(AllowAllKeys())
client.connect(HOST, username=USER, password=PASSWORD)
channel = client.invoke_shell()
stdin = channel.makefile('wb')
stdout = channel.makefile('rb')
stdin.write('''
cd tmp
ls
exit
''')
print stdout.read()
stdout.close()
stdin.close()
client.close()
这种方法可以工作(我已经这样做了),但需要一些时间,并且它使用特定于unix的调用。您必须放弃子进程模块,并基于fork/exec和os.pipe()滚动您自己的等效子进程模块。
使用fcntl。使用os.pipe()创建后,将子进程的stdin/stdout文件描述符(读和写)置于非阻塞模式(O_NONBLOCK选项常量)。
使用select。选择轮询函数或等待文件描述符的可用性。为了避免死锁,您需要使用select()来确保写操作不会阻塞,就像读操作一样。即便如此,在读写时也必须考虑到OSError异常,并在遇到EAGAIN错误时重试。(即使在读/写之前使用select, EAGAIN也可以在非阻塞模式下发生;这是一个常见的内核错误,已被证明很难修复。
如果你愿意在Twisted框架上实现,他们应该已经为你解决了这个问题;你所要做的就是写一个Process子类。但是我自己还没有试过。