如何在 paramiko 中写入标准输入(从 exec_command 返回)?

Posted

技术标签:

【中文标题】如何在 paramiko 中写入标准输入(从 exec_command 返回)?【英文标题】:How do I write to stdin (returned from exec_command) in paramiko? 【发布时间】:2018-07-11 06:59:03 【问题描述】:

我正在尝试使用 paramiko 写入自定义程序的标准输入。这是一个最小(非)工作示例:

~/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】:

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.

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

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] #

【讨论】:

关键点是 read() 会一直读取到 EOF。要么我需要关闭 stdin - 这是一个相当永久的解决方案 - 要么我需要使用 stdin.read(N) 其中 N 添加了一个简单的例子来显示 close() 和 shutdown_write() 之间的差异。 在 python3 上, sys.stdout.write(stdout.read() ) 需要 .decode() 才能工作,它应该是 sys.stdout.write(stdout.read().decode() )否则会引发TypeError: write() argument must be str, not bytes

以上是关于如何在 paramiko 中写入标准输入(从 exec_command 返回)?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Python 中执行将数据写入标准输入的进程?

在 Rust 中写入子进程的标准输入?

Erlang 读标准输入 写标准输出

从线程中的标准输入读取以写入 c 中的文件

如何在 linux 系统上用 PHP 启动后台进程并将用户 ajax 输入重复写入其标准输入

如何将数据写入 Python shell 管道中第一个进程的标准输入?