I am trying to write to a custom program's stdin with paramiko. Here is a minimal (non-)working example:
~/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)
Then I do these commands in 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()
Unfortunately, nothing then appears in ~/LOG. However, if I do
$ ~/stdin_to_file.py < some_other_file
The contents of some_other_file appear in ~/LOG.
Can anyone suggest where I've gone wrong? It seems like I'm doing the logical thing. None of these work either:
stdin.channel.send('hi')
using the get_pty parameter
sending the output of cat - to stdin_to_file.py
You can get the output the command by using stdout. read() (returns a string) or stdout. readlines() (returns a list of lines).
SSHClient. A high-level representation of a session with an SSH server. This class wraps Transport , Channel , and SFTPClient to take care of most aspects of authenticating and opening channels. A typical use case is: client = SSHClient() client.
So, we have created a client object “ssh” of “SSHClient” with the paramiko package. This object calls the automatic policy function of adding unknown keys to perform SSH to remote host servers via the paramiko package. The same object is used to connect the client machine with the host server via the host credentials.
Paramiko helps you automate repetitive system administration tasks on remote servers. More advanced Paramiko programs send the lines of a script one at a time. It does this rather than transacting all of a command, such as df or last , synchronously to completion.
sys.stdin.read()
will keep reading until EOF so in your paramiko script you need to close the stdin
(returned from exec_command()
). But how?
stdin.close()
would not work.According to Paramiko's doc (v1.16):
Warning: To correctly emulate the file object created from a socket’s
makefile()
method, aChannel
and itsChannelFile
should be able to be closed or garbage-collected independently. Currently, closing theChannelFile
does nothing but flush the buffer.
stdin.channel.close() also has problem.
Since stdin, stdout and stderr all share one single channel, stdin.channel.close()
will also close stdout and stderr which is not expected.
stdin.channel.shutdown_write()
The correct solution is to use stdin.channel.shutdown_write()
which disallows writing to the channel but still allows reading from the channel so stdout.read()
and stderr.read()
would still work.
See following example to see the difference between stdin.channel.close()
and 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] #
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With