问题
您的问题是①ssh.stdout.readlines() 正在读取所有现有输入,这些输入已经缓冲到您正在访问它的点,并按行尾分隔(\r 或 \n)。
但是因为是打开提示,所以②可能只有一行,即>>>,没有行尾。
处理流
你需要做的是创建一个while循环来读取输出:
def handle_output(out):
while True:
out_line = out.readline()
print("OUT: {}".format(out_line))
def handle_errput(err):
while True:
err_line = err.readline()
print("ERR: {}".format(err_line))
这样就可以了:
handle_output(ssh.stdout)
handle_errput(ssh.stderr)
然后,一旦远程 python 解释器打印出完整的行,您的控制台上就会显示一些内容。但这只能解决①。
您仍然需要让远程进程输出至少一整行,而这样做的唯一方法是实际向它发送数据!
所以你想添加另一个功能:
def handle_input(inp):
while True:
inp_line = sys.stdin.readline()
inp.write(inp_line)
你会这样称呼它:
handle_input(ssh.stdin)
这样就解决了②。
并行读取
带线程
但是现在,如果你这样做了,从逻辑上讲,你还有另一个问题:
handle_output(ssh.stdout)
handle_errput(ssh.stderr)
handle_input(ssh.stdin)
您的程序流永远不会到达handle_errput() 或handle_input(),因为它会卡在handle_output() 无限循环中。
解决方案是并行执行三个循环:
out_thread = Thread(target=handle_output, args=(ssh.stdout,))
err_thread = Thread(target=handle_errput, args=(ssh.stderr,))
try:
out_thread.start()
err_thread.start()
handle_input()
finally:
out_thread.join()
err_thread.join()
这样从外部进程读取将发生在另一个线程中,而写入将发生在当前线程中。您也可以启动三个线程(一个用于读取 stdout,一个用于读取 stderr,一个用于写入)并让主线程运行一个循环,该循环将执行“处理”并与这些线程通信(提示:使用 threading.Queue 进行交换线程之间的数据)。
带有事件库(仅限 py3)
如果您使用异步库like asyncio offered with python 3(对于 py2,您可以使用 tornado 或 greenlet),您可以避免使用多线程以及线程间通信的痛苦,这将为您提供一个非常好的抽象,而不是使用 select() :
async def handle_output(out):
while True:
await out_line = out.readline()
print("OUT: {}".format(out_line))
async def handle_errput(err):
while True:
await err_line = err.readline()
print("ERR: {}".format(err_line))
async def handle_input(inp):
while True:
await inp_line = sys.stdin.readline()
inp.write(inp_line)
asyncio.Task(handle_output(ssh.stdout))
asyncio.Task(handle_errput(ssh.stderr))
asyncio.Task(handle_input(ssh.stdin))
asyncio.get_event_loop().run_forever()
使用 select() 调用
在 python 2 中,最好和最简单(但远非最简单)的实现方式是使用select():
基本上一个选择调用会看起来像:
while True:
readable, writable, excepts = select.select(
[ssh.stdout, ssh.stderr], # outputs to watch
[sys.stdin], # inputs to watch
[ssh.stdout, ssh.stderr], # exceptions to watch
1) # timeout
for r in readable:
print(r.read())
for w in writable:
p.stdin.write(w.read())
但你最好read a thorough documentation about select()。
从那里去哪里?
我希望能够从主机 python 脚本提交命令,例如 ssh.execute("1+1")。这基本上会告诉 python2 计算 1+1。然后我想将输出读回主机 python 脚本。
我给你的解决方案是帮助你处理从终端到远程 python 进程的透明通信。它暴露了实现上述所有工具所缺少的所有工具,除了一个,如何在 3 个循环之间进行通信?
最简单的方法是使用三个队列,两个处理从远程进程传入的结果,最后一个处理传出命令:
input_queue = queue.Queue()
output_queue = queue.Queue()
errput_queue = queue.Queue()
然后在你的主线程中你可以实现:
def remote_python_execute(command, output_queue, errput_queue):
# send a command to the remote process
input_queue.put(command)
out, err = ([], [])
# read the output and then the errput as long as
# there's something to read
while not output_queue.empty():
out.append(output_queue.get())
while not errput_queue.empty():
err.append(errput_queue.get())
return out, err
你的 handle_output 函数看起来像(你可以适应两者:
def handle_output(out, output_queue):
while True:
output_queue.put(out.readline())
只是给你一个想法......现在轮到你填补空白并选择最适合你的需求?
免责声明:此答案包含未经测试的代码,旨在为您提供有关如何实现所需目标的方向。不要复制/粘贴它,而是阅读文档并了解您在做什么。还要小心使用线程,作为提示,切勿在两个线程中使用变量,否则您可能会被咬。很难。
HTH