I am trying to combine the output of stdout and stderr. My belief is that this can be done with the set_combine_stderr() of a Channel object.
This is what I am doing:
SSH = paramiko.SSHClient()
#I connect and everything OK, then:
chan = ssh.invoke_shell()
chan.set_combine_stderr(True)
chan.exec_command('python2.6 subir.py')
resultado = chan.makefile('rb', -1.)
However, I get the following error when I try to store the result (last line above, chan.makefile() ):
Error: Channel closed.
Any help would be greatly appreciated
While it is true that set_combine_stderr diverts stderr to the stdout stream, it does so in chaotic order, so you do not get the result you probably want, namely, the lines combined in the order written, as if you were running the command in a local terminal window. Instead, use get_pty. That will cause the server to run the lines through a pseudo-terminal, keeping them in chronological sequence.
Here's a test program, outerr.py, that writes alternating lines on stdout and stdin. Assume it's sitting in the home directory of llmps#meerkat2.
#!/usr/bin/env python
import sys
for x in xrange(1, 101):
(sys.stdout, sys.stderr)[x%2].write('This is line #%s, on std%s.\n' %
(x, ('out', 'err')[x%2]))
Now try the following code to run it remotely:
#!/usr/bin/env python
import paramiko
def connect():
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('meerkat2', username='llmps', password='..')
return ssh
def runTest(ssh):
tran = ssh.get_transport()
chan = tran.open_session()
# chan.set_combine_stderr(True)
chan.get_pty()
f = chan.makefile()
chan.exec_command('./outerr.py')
print f.read(),
if __name__ == '__main__':
ssh = connect()
runTest(ssh)
ssh.close()
If you run the above, you should see 100 lines in order as written. If, instead, you comment out the chan.get_pty() call and uncomment the chan.set_combine_stderr(True) call, you will get clumps of stdout and stderr lines interspersed randomly from run to run.
Ok, I know this is quite an old topic, but I run into the same problem and I got a (maybe not-so-)pretty solution. Just call the command on the remote server redirecting the stderr to stdout and then always read from the stdout. For example:
client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('hostname', username='user', password='pass')
stdin,stdout,stderr = client.exec_command('python your_script.py 2> \&1')
print stdout.read()
#AaronMcSmooth: I am referring to the stdout and stderr of the computer I am connecting to (via SSH).
I ended up doing this:
stdin, stdout, stderr = ssh.exec_command(...)
output = stdin.read().strip() + stdout.read().strip()
For the purpose of my application, it doesn't matter to distinguish between stdout and stderr, but I don't think that's the best way to combine the two.
The code of SSHClient.exec_command() is (looking at paramiko's source code):
def exec_command(self, command, bufsize=-1):
chan = self._transport.open_session()
chan.exec_command(command)
stdin = chan.makefile('wb', bufsize)
stdout = chan.makefile('rb', bufsize)
stderr = chan.makefile_stderr('rb', bufsize)
return stdin, stdout, stderr
I am performing the same actions on the channel but receive the Channel is closed error.
Related
I wrote this code in Paramiko:
ssh = SSHClient()
ssh.set_missing_host_key_policy(AutoAddPolicy())
ssh.connect(hostname, username=user, password=passwd, timeout=3)
session = ssh.invoke_shell()
session.send("\n")
session.send("echo step 1\n")
time.sleep(1)
session.send("sleep 30\n")
time.sleep(1)
while not session.recv_ready():
time.wait(2)
output = session.recv(65535)
session.send("echo step 2\n")
time.sleep(1)
output += session.recv(65535)
I'm trying execute more commands on my Linux server. The problem is my Python code not wait to finish execute command, for example if I'm try to execute sleep 30, the Python not wait 30 seconds for finish execute commands. How can resolve this problem ? I tried with while recv_ready(), but it still does not wait.
Use exec_command: http://docs.paramiko.org/en/1.16/api/channel.html
stdin, stdout, stderr = ssh.exec_command("my_long_command --arg 1 --arg 2")
The following code works for me:
from paramiko import SSHClient, AutoAddPolicy
import time
ssh = SSHClient()
ssh.set_missing_host_key_policy(AutoAddPolicy())
ssh.connect('111.111.111.111', username='myname', key_filename='/path/to/my/id_rsa.pub', port=1123)
sleeptime = 0.001
outdata, errdata = '', ''
ssh_transp = ssh.get_transport()
chan = ssh_transp.open_session()
# chan.settimeout(3 * 60 * 60)
chan.setblocking(0)
chan.exec_command('ls -la')
while True: # monitoring process
# Reading from output streams
while chan.recv_ready():
outdata += chan.recv(1000)
while chan.recv_stderr_ready():
errdata += chan.recv_stderr(1000)
if chan.exit_status_ready(): # If completed
break
time.sleep(sleeptime)
retcode = chan.recv_exit_status()
ssh_transp.close()
print(outdata)
print(errdata)
Please note that command history cannot be executed with ssh as is.
See example here: https://superuser.com/questions/962001/incorrect-output-of-history-command-of-ssh-how-to-read-the-timestamp-info-corre
In case you do not need to read the stdout and stderr separately, you can use way more straightforward code:
stdin, stdout, stderr = ssh_client.exec_command(command)
stdout.channel.set_combine_stderr(True)
output = stdout.readlines()
The readlines reads until the command finishes and returns a complete output.
In case you need the output separately, do not be tempted to remove the set_combine_stderr and call readlines on stdout and stderr separately. That might deadlock. See Paramiko ssh die/hang with big output
For a correct code that reads the outputs separately, see Run multiple commands in different SSH servers in parallel using Python Paramiko.
Obligatory warning: Do not use AutoAddPolicy – You are losing a protection against MITM attacks by doing so. For a correct solution, see Paramiko "Unknown Server".
I wrote this code in Paramiko:
ssh = SSHClient()
ssh.set_missing_host_key_policy(AutoAddPolicy())
ssh.connect(hostname, username=user, password=passwd, timeout=3)
session = ssh.invoke_shell()
session.send("\n")
session.send("echo step 1\n")
time.sleep(1)
session.send("sleep 30\n")
time.sleep(1)
while not session.recv_ready():
time.wait(2)
output = session.recv(65535)
session.send("echo step 2\n")
time.sleep(1)
output += session.recv(65535)
I'm trying execute more commands on my Linux server. The problem is my Python code not wait to finish execute command, for example if I'm try to execute sleep 30, the Python not wait 30 seconds for finish execute commands. How can resolve this problem ? I tried with while recv_ready(), but it still does not wait.
Use exec_command: http://docs.paramiko.org/en/1.16/api/channel.html
stdin, stdout, stderr = ssh.exec_command("my_long_command --arg 1 --arg 2")
The following code works for me:
from paramiko import SSHClient, AutoAddPolicy
import time
ssh = SSHClient()
ssh.set_missing_host_key_policy(AutoAddPolicy())
ssh.connect('111.111.111.111', username='myname', key_filename='/path/to/my/id_rsa.pub', port=1123)
sleeptime = 0.001
outdata, errdata = '', ''
ssh_transp = ssh.get_transport()
chan = ssh_transp.open_session()
# chan.settimeout(3 * 60 * 60)
chan.setblocking(0)
chan.exec_command('ls -la')
while True: # monitoring process
# Reading from output streams
while chan.recv_ready():
outdata += chan.recv(1000)
while chan.recv_stderr_ready():
errdata += chan.recv_stderr(1000)
if chan.exit_status_ready(): # If completed
break
time.sleep(sleeptime)
retcode = chan.recv_exit_status()
ssh_transp.close()
print(outdata)
print(errdata)
Please note that command history cannot be executed with ssh as is.
See example here: https://superuser.com/questions/962001/incorrect-output-of-history-command-of-ssh-how-to-read-the-timestamp-info-corre
In case you do not need to read the stdout and stderr separately, you can use way more straightforward code:
stdin, stdout, stderr = ssh_client.exec_command(command)
stdout.channel.set_combine_stderr(True)
output = stdout.readlines()
The readlines reads until the command finishes and returns a complete output.
In case you need the output separately, do not be tempted to remove the set_combine_stderr and call readlines on stdout and stderr separately. That might deadlock. See Paramiko ssh die/hang with big output
For a correct code that reads the outputs separately, see Run multiple commands in different SSH servers in parallel using Python Paramiko.
Obligatory warning: Do not use AutoAddPolicy – You are losing a protection against MITM attacks by doing so. For a correct solution, see Paramiko "Unknown Server".
I'm trying to make a python script which is going run a bash script on a remote machine via ssh and then parse its output. The bash script outputs lot of data (like 5 megabytes of text / 50k lines) in stdout and here is a problem - I'm getting all the data only in ~10% cases. In other 90% cases I'm getting about 97% of what i expect and it looks like it always trims at the end. This is how my script looks like:
import subprocess
import re
import sys
import paramiko
def run_ssh_command(ip, port, username, password, command):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(ip, port, username, password)
stdin, stdout, stderr = ssh.exec_command(command)
output = ''
while not stdout.channel.exit_status_ready():
solo_line = ''
# Print stdout data when available
if stdout.channel.recv_ready():
# Retrieve the first 1024 bytes
solo_line = stdout.channel.recv(2048).
output += solo_line
ssh.close()
return output
result = run_ssh_command(server_ip, server_port, login, password, 'cat /var/log/somefile')
print "result size: ", len(result)
I'm pretty sure that problem is in overflowing of some internal buffer, but which one and how to fix it?
Thank you very much for any tip!
When stdout.channel.exit_status_ready() starts returning True, there might still be a lot of data on the remote side, waiting to be sent. But you only receive one more chunk of 2048 bytes and quit.
Instead of checking the exit status, you could keep calling recv(2048) until it returns an empty string, which means that no more data is coming:
output = ''
next_chunk = True
while next_chunk:
next_chunk = stdout.channel.recv(2048)
output += next_chunk
But really you probably just want:
output = stdout.read()
May I suggest a less crude way to execute command over ssh via Fabric library.
It may look like this (omitting ssh authentication details):
from fabric import Connection
with Connection('user#localhost') as con:
res = con.run('~/test.sh', hide=True)
lines = res.stdout.split('\n')
print('{} lines readen.'.format(len(lines)))
given the test script ~/test.sh
#!/bin/sh
for i in {1..1234}
do
echo "Line $i"
done
all of the output is correctly consumed
How do I execute multiple commands using Paramiko and read the output back into my python script?
This question is theoretically answered here How do you execute multiple commands in a single session in Paramiko? (Python), but in my view that answer is incorrect.
The problem is that when you read the stdout, it reads the entire content of the terminal including the program that you "typed" into the terminal.
Just try it (this is basically a copy paste from the above thread):
import paramiko
machine = "you machine ip"
username = "you username"
password = "password"
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(machine, username = username, 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()
So my question is, how do I execute multiple commands and read only the output of those commands, rather than the input I "typed" and the output?
Thanks in advance for your kind help and time.
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
target_host = 'x.x.x.x'
target_port = 22
target_port = 22
pwd = ':)'
un = 'root'
ssh.connect( hostname = target_host , username = un, password =pwd)
#Now exeute multiple commands seperated by semicolon
stdin, stdout, stderr = ssh.exec_command('cd mydir;ls')
print stdout.readlines()
You're seeing the commands you typed because the shell echoes them back. You can turn this off by running
stty -echo
before your other commands.
Another approach is to not invoke an interactive shell, but just run the commands directly, unless there's some other reason you especially need an interactive shell. For instance you could say
client.exec_command('/bin/sh -c "cd /tmp && ls")
If you want a shell but without a pty, you can try
client.exec_command('/bin/sh')
and I think that will suppress the echo too.
This should work:
# Explicitly provide key, ip address and username
from paramiko import SSHClient, AutoAddPolicy
result = []
def ssh_conn():
client = SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(AutoAddPolicy())
client.connect('<host_IP_address>', username='<your_host_username>', key_filename='<private_key_location>')
stdin, stdout, stderr = client.exec_command('ls -la')
for each_line in stdout:
result.append(each_line.strip('\n'))
client.close()
ssh_conn()
for each_line in result:
print(each_line.strip())
so I was working with paramiko for some basic SSH testing and I'm not getting any output into stdout. Heres my code.
import paramiko
client=paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
com="ls ~/desktop"
client.connect('MyIPAddress',MyPortNumber, username='username', password='password')
output=""
stdin, stdout, stderr = client.exec_command(com)
print "ssh succuessful. Closing connection"
client.close()
print "Connection closed"
stdout=stdout.readlines()
print stdout
print com
for line in stdout:
output=output+line
if output!="":
print output
else:
print "There was no output for this command"
So whenever I run this, the command is executed (as seen by if I do something like a cp, the file is copied), but I always get "There was no output for this command". When stdout=stdout.readlines() is printed, [] is the output. In addition, if I add a print statement into the for loop, it never gets run. Could someone help me out here? Thanks!
You have closed the connection before reading lines:
import paramiko
client=paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
com="ls ~/desktop"
client.connect('MyIPAddress',MyPortNumber, username='username', password='password')
output=""
stdin, stdout, stderr = client.exec_command(com)
print "ssh succuessful. Closing connection"
stdout=stdout.readlines()
client.close()
print "Connection closed"
print stdout
print com
for line in stdout:
output=output+line
if output!="":
print output
else:
print "There was no output for this command"
The code in the accepted answer may hang, if the command produces also an error output. See Paramiko ssh die/hang with big output.
An easy solution, if you do not mind merging stdout and stderr, is to combine them into one stream using Channel.set_combine_stderr:
stdin, stdout, stderr = client.exec_command(command)
stdout.channel.set_combine_stderr(True)
output = stdout.readlines()
If you need to read the outputs separately, see Run multiple commands in different SSH servers in parallel using Python Paramiko.
*Interactive example :
====Part 1, this show the sh output in server ,at the end of is ">"
need some input to continual or exit ======
selilsosx045:uecontrol-CXC_173_6456-R32A01 lteue$ ./uecontrol.sh -host localhost
UE Control:Start UE control using:
UE Control:java -Dlogdir= -Duecontrol.configdir=./etc -jar ./server/server-R32A01.jar -host localhost
Loading properties from file /Users/lteue/Downloads/uecontrol-CXC_173_6456-R32A01/etc/uecontrol.properties
Starting remote CLI towards host localhost
Enter the command Q to exit the CLI, or the command HELP
to get information on available commands.
The CLI is ready for input.
uec>
===========Pyhton code with peramiko ============*
Try below method : while not stdout.channel.exit_status_ready():
def shCommand(server_list):
server_IP = server_list[0]
username = server_list[1]
password = server_list[2]
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(server_IP,22,username, password)strong text
commandList = ['list \n']
alldata = getUeInfo(ssh,commandList)
ssh.close()
def getUeInfo(ssh,commandList):
data_buffer = ""
num_of_input = 0
stdin, stdout, stderr = ssh.exec_command('cmd')
while not stdout.channel.exit_status_ready():
solo_line = ""
if stdout.channel.recv_ready():
solo_line = stdout.channel.recv(1024) # Retrieve the first 1024 bytes
data_buffer += solo_line
if(cmp(solo_line,'uec> ') ==0 ): #len of solo should be 5 ,
if num_of_input == 0 :
data_buffer = ""
for cmd in commandList :
#print cmd
stdin.channel.send(cmd)
num_of_input += 1
if num_of_input == 1 :
stdin.channel.send('q \n')
num_of_input += 1
return data_buffer
As #jabaldonedo said you closed your SSHClient connection before reading the stdout. SSHClient can be used as a context manager. Using the SSHClient as a context manager helps prevent you from trying to access stdout and stderr after the ssh connection is closed. The resulting code in Python3 syntax looks like:
from paramiko import AutoAddPolicy, SSHClient
with SSHClient() as client:
client.set_missing_host_key_policy(AutoAddPolicy)
client.connect(
'MyIPAddress',
MyPortNumber,
username='username',
password='password'
)
com = "ls ~/desktop"
stdin, stdout, stderr = client.exec_command(com)
output = ''
for line in stdout.readlines()
output += line
if output:
print(output)
else:
print("There was no output for this command")
# Program to print the output in console/interpreter/shell in runtime without using stdout.
import paramiko
import xlrd
import time
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
loc = ('/Users/harshgow/Documents/PYTHON_WORK/labcred.xlsx')
wo = xlrd.open_workbook(loc)
sheet = wo.sheet_by_index(0)
Host = sheet.cell_value(0, 1)
Port = int(sheet.cell_value(3, 1))
User = sheet.cell_value(1, 1)
Pass = sheet.cell_value(2, 1)
def details(Host, Port, User, Pass):
time.sleep(2)
ssh.connect(Host, Port, User, Pass)
print('connected to ip ', Host)
stdin = ssh.exec_command("")
remote_conn = ssh.invoke_shell()
print("Interactive SSH session established")
output = remote_conn.recv(1000)
remote_conn.send("\n")
remote_conn.send("xstatus Cameras\n")
time.sleep(5)
output = remote_conn.recv(10000)
print(output)
details(Host, Port, User, Pass)