如何在paramiko中写入stdin(从exec_command返回)?

时间:2018-02-01 02:33:56

标签: python unix paramiko ssh-tunnel

我正在尝试用paramiko写一个自定义程序的stdin。这是一个最小(非)工作的例子:

〜/ stdin_to_file.py:

#! /usr/bin/python

import time, sys
f = open('/home/me/LOG','w')
while True:
    sys.stdin.flush()
    data = sys.stdin.read()
    f.write(data+'\n\n')
    f.flush()
    time.sleep(0.01)

然后我在IPython中执行这些命令:

import paramiko
s = paramiko.client.SSHClient 
s.load_system_host_keys()
s.connect('myserver')
stdin, stdout, stderr = s.exec_command('/home/me/stdin_to_file.py')
stdin.write('Hello!')
stdin.flush()

不幸的是,〜/ LOG中没有任何内容。但是,如果我这样做

$ ~/stdin_to_file.py < some_other_file

some_other_file的内容出现在〜/ LOG。

任何人都可以建议我出错的地方吗?看起来我做的是合乎逻辑的事情。这些都不起作用:

stdin.channel.send('hi')
using the get_pty parameter
sending the output of cat - to stdin_to_file.py

1 个答案:

答案 0 :(得分:6)

sys.stdin.read()将继续阅读直至EOF,因此在您的paramiko脚本中,您需要关闭stdin(从exec_command()返回)。但是如何?

1。 stdin.close()无效。

根据Paramiko的文件( v1.16 ):

  

警告:要正确模拟从套接字makefile()方法创建的文件对象,Channel及其ChannelFile应该可以关闭或者垃圾 - 独立收集。 目前,关闭ChannelFile只会刷新缓冲区。

2。 stdin.channel.close() also has problem.

由于 stdin stdout stderr 都共享一个通道,stdin.channel.close()也会关闭 stdout stderr 这是不期望的。

3。 stdin.channel.shutdown_write()

正确的解决方案是使用不允许写入频道的stdin.channel.shutdown_write(),但仍然允许从频道进行阅读,以便stdout.read()stderr.read()仍可使用。

请参阅以下示例,了解stdin.channel.close()stdin.channel.shutdown_write()之间的区别。

[STEP 101] # cat foo.py
import paramiko, sys, time

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy() )
ssh.connect(hostname='127.0.0.1', username='root', password='password')
cmd = "sh -c 'read v; sleep 1; echo $v'"
stdin, stdout, stderr = ssh.exec_command(cmd)
if sys.argv[1] == 'close':
    stdin.write('hello world\n')
    stdin.flush()
    stdin.channel.close()
elif sys.argv[1] == 'shutdown_write':
    stdin.channel.send('hello world\n')
    stdin.channel.shutdown_write()
else:
    raise Exception()
sys.stdout.write(stdout.read() )
[STEP 102] # python foo.py close           # It outputs nothing.
[STEP 103] # python foo.py shutdown_write  # This works fine.
hello world
[STEP 104] #