I'm rewriting a Bash script I wrote into Python. The crux of that script was
ssh -t first.com "ssh second.com very_remote_command"
I'm having a problem with the nested authentication with paramiko. I wasn't able to find any examples dealing with my precise situation, but I was able to find examples with sudo on a remote host.
The first method writes to stdin
ssh.connect('127.0.0.1', username='jesse', password='lol')
stdin, stdout, stderr = ssh.exec_command("sudo dmesg")
stdin.write('lol\n')
stdin.flush()
The second creates a channel and uses the socket-like send and recv.
I was able to get stdin.write to work with sudo, but it doesn't work with ssh on the remote host.
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('first.com', username='luser', password='secret')
stdin, stdout, stderr = ssh.exec_command('ssh luser#second.com')
stdin.write('secret')
stdin.flush()
print '---- out ----'
print stdout.readlines()
print '---- error ----'
print stderr.readlines()
ssh.close()
...prints...
---- out ----
[]
---- error ----
['Pseudo-terminal will not be allocated because stdin is not a terminal.\r\n', 'Permission denied, please try again.\r\n', 'Permission denied, please try again.\r\n', 'Permission denied (publickey,password,keyboard-interactive).\r\n']
The pseudo-terminal error reminded me of the -t flag in my original command, so I switched to the second method, using a Channel. Instead of ssh.exec_command and later, I have:
t = ssh.get_transport()
chan = t.open_session()
chan.get_pty()
print '---- send ssh cmd ----'
print chan.send('ssh luser#second.com')
print '---- recv ----'
print chan.recv(9999)
chan = t.open_session()
print '---- send password ----'
print chan.send('secret')
print '---- recv ----'
print chan.recv(9999)
...but it prints '---- send ssh cmd ----' and just hangs until I kill the process.
I'm new to Python and none too knowledgeable about networks. In the first case, why does sending the password work with sudo but not with ssh? Are the prompts different? Is paramiko even the right library for this?
I managed to find a solution, but it requires a little manual work. If anyone have a better solution, please tell me.
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('first.com', username='luser', password='secret')
chan = ssh.invoke_shell()
# Ssh and wait for the password prompt.
chan.send('ssh second.com\n')
buff = ''
while not buff.endswith('\'s password: '):
resp = chan.recv(9999)
buff += resp
# Send the password and wait for a prompt.
chan.send('secret\n')
buff = ''
while not buff.endswith('some-prompt$ '):
resp = chan.recv(9999)
buff += resp
# Execute whatever command and wait for a prompt again.
chan.send('ls\n')
buff = ''
while not buff.endswith('some-prompt$ '):
resp = chan.recv(9999)
buff += resp
# Now buff has the data I need.
print 'buff', buff
ssh.close()
The thing to note is that instead of this
t = ssh.get_transport()
chan = t.open_session()
chan.get_pty()
...you want this
chan = ssh.invoke_shell()
It reminds me of when I tried to write a TradeWars script when I was a kid and gave up coding for ten years. :)
Here is a small example using paramiko only (and port forwarding):
import paramiko as ssh
class SSHTool():
def __init__(self, host, user, auth,
via=None, via_user=None, via_auth=None):
if via:
t0 = ssh.Transport(via)
t0.start_client()
t0.auth_password(via_user, via_auth)
# setup forwarding from 127.0.0.1:<free_random_port> to |host|
channel = t0.open_channel('direct-tcpip', host, ('127.0.0.1', 0))
self.transport = ssh.Transport(channel)
else:
self.transport = ssh.Transport(host)
self.transport.start_client()
self.transport.auth_password(user, auth)
def run(self, cmd):
ch = self.transport.open_session()
ch.set_combine_stderr(True)
ch.exec_command(cmd)
retcode = ch.recv_exit_status()
buf = ''
while ch.recv_ready():
buf += ch.recv(1024)
return (buf, retcode)
# The example below is equivalent to
# $ ssh 10.10.10.10 ssh 192.168.1.1 uname -a
# The code above works as if these 2 commands were executed:
# $ ssh -L <free_random_port>:192.168.1.1:22 10.10.10.10
# $ ssh 127.0.0.1:<free_random_port> uname -a
host = ('192.168.1.1', 22)
via_host = ('10.10.10.10', 22)
ssht = SSHTool(host, 'user1', 'pass1',
via=via_host, via_user='user2', via_auth='pass2')
print ssht.run('uname -a')
You can create ssh connection using channel from another ssh connection. See here for more detail.
For a ready made solution check out pxssh from the pxpect project. Look at the sshls.py and ssh_tunnel.py examples.
http://www.noah.org/wiki/Pexpect
Sinas's answer works well but didn't provide all the output from very long commands for me. However, using chan.makefile() allows me to retrieve all the output.
The below works on a system that requires tty and also prompts for sudo password
ssh = paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.WarningPolicy())
ssh.connect("10.10.10.1", 22, "user", "password")
chan=ssh.get_transport().open_session()
chan.get_pty()
f = chan.makefile()
chan.exec_command("sudo dmesg")
chan.send("password\n")
print f.read()
ssh.close()
Related
I'm trying to achieve some automation with python and paramiko (with my basic beginner logic).
The code below I'm happy to say works. Until I add in the command 'rm -f testtrace.pcap to delete the file once it has been downloaded via sftp.
Define login credentials
host = input("Host: ")
user = input("User: ")
port = 22
password = getpass("Password: ")
Open ssh connection
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(host, port=port, username=user, password=password)
Execute command run tcpdump
stdin, stdout, stderr = ssh.exec_command('timeout 10 tcpdump port 5060 -nnv -s 0 -w testtrace.pcap')
channel = stdout.channel
channel.recv_exit_status()
ssh.close()
Open sftp connection
transport = paramiko.Transport((host, port))
transport.connect(username=user, password=password)
sftp = paramiko.SFTPClient.from_transport(transport)
File Download
filepath = '/root/testtrace.pcap'
localpath = 'C:\\Users\\******\\Desktop\\python\\testtrace.pcap'
sftp.get(filepath, localpath)
Execute command delete file
stdin, stdout, stderr = ssh.exec_command('rm -f testtrace.pcap')
channel = stdout.channel
channel.recv_exit_status()
ssh.close()
Right so a problem that I've been struggling with for a day or two, I've manage to solve within 10 minute of signing up to Stackoverflow!.
Execute command run tcpdump
stdin, stdout, stderr = ssh.exec_command('timeout 10 tcpdump port 5060 -nnv -s 0 -w testtrace.pcap')
channel = stdout.channel
channel.recv_exit_status()
I was closing the ssh connection too early. By removing ssh.close() from this section it appears to have solved the issue and now functions correctly.
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())
I am trying to execute a sudo command on a remote machine using python-paramiko, when I execute the command, I bind it with 3 streams, and I use the input stream to pass the password, but it doesn't work, this is the traceback result:
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "/usr/local/lib/python2.7/dist-packages/paramiko/file.py", line 314, in write
self._write_all(data)
File "/usr/local/lib/python2.7/dist-packages/paramiko/file.py", line 439, in _write_all
count = self._write(data)
File "/usr/local/lib/python2.7/dist-packages/paramiko/channel.py", line 1263,in _write
self.channel.sendall(data)
File "/usr/local/lib/python2.7/dist-packages/paramiko/channel.py", line 796, in sendall
raise socket.error('Socket is closed')
error: Socket is closed
and this is my python code:
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('192.168.0.104', username='cdc',password='123456')
stdin, stdout, stderr = ssh.exec_command("sudo dmesg")
stdin.write("123456\n")
stdin.flush()
print stdout.readlines()
ssh.close()
Any help? Thanks in advance
First of all, have you tried in console with ssh cdc#192.168.0.104 "sudo -S -p '' dmesg". If it also fails, then you might check the sshd settings and the sudoer settings.
If it works well, please add some echo between lines, so that we can know exactly when the exception was thrown. I highly doubt that you should change sudo dmesg to sudo -S -p '' dmesg.
You might also try my wrapper of paramiko. I can use it smoothly to access any CentOS/SuSE node and perform any commands (w/wo sudo privilege):
#!/usr/bin/python
from StringIO import StringIO
import paramiko
class SshClient:
"A wrapper of paramiko.SSHClient"
TIMEOUT = 4
def __init__(self, host, port, username, password, key=None, passphrase=None):
self.username = username
self.password = password
self.client = paramiko.SSHClient()
self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
if key is not None:
key = paramiko.RSAKey.from_private_key(StringIO(key), password=passphrase)
self.client.connect(host, port, username=username, password=password, pkey=key, timeout=self.TIMEOUT)
def close(self):
if self.client is not None:
self.client.close()
self.client = None
def execute(self, command, sudo=False):
feed_password = False
if sudo and self.username != "root":
command = "sudo -S -p '' %s" % command
feed_password = self.password is not None and len(self.password) > 0
stdin, stdout, stderr = self.client.exec_command(command)
if feed_password:
stdin.write(self.password + "\n")
stdin.flush()
return {'out': stdout.readlines(),
'err': stderr.readlines(),
'retval': stdout.channel.recv_exit_status()}
if __name__ == "__main__":
client = SshClient(host='host', port=22, username='username', password='password')
try:
ret = client.execute('dmesg', sudo=True)
print " ".join(ret["out"]), " E ".join(ret["err"]), ret["retval"]
finally:
client.close()
Im sorry i dont have time for details answer but i was able to implement sudo commands on paramiko using this advise
#!/usr/bin/env python
import paramiko
l_password = "yourpassword"
l_host = "yourhost"
l_user = "yourusername"
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(l_host, username=l_user, password=l_password)
transport = ssh.get_transport()
session = transport.open_session()
session.set_combine_stderr(True)
session.get_pty()
#for testing purposes we want to force sudo to always to ask for password. because of that we use "-k" key
session.exec_command("sudo -k dmesg")
stdin = session.makefile('wb', -1)
stdout = session.makefile('rb', -1)
#you have to check if you really need to send password here
stdin.write(l_password +'\n')
stdin.flush()
for line in stdout.read().splitlines():
print 'host: %s: %s' % (l_host, line)
I know this question is kind of old but I was wanting to use sudo and paramiko together, too. It took me a while to figure out this solution. It may not work for everyone but I figured it was worth adding.
def ssh_handler(hostname, username=USER, password=PASS, command=CMD):
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname,
username=username,
password=password)
# set get_pty to True to get a pseudo terminal
stdin, stdout, stderr = ssh.exec_command(prepare_command(command), get_pty=True)
# write and flush the password to the remote terminal
# note that the password will also be written to the terminal from where the script is executed.
stdin.write(password+'\n')
stdin.flush()
response = stdout.read()
ssh.close()
print(response)
def prepare_command(command):
if (not isinstance(command, basestring)):
command = ' ; '.join(command)
command = command.replace('"','\"')
command = 'sudo -s -- " '+command+' " \n'
return command
# kind of a dumb example but you get the point
mycmd = [];
mycmd.append('cd /dir/this/user/doesnt/have/access/to')
mycmd.append('ls -las')
mycmd.append('cat file_in_dir.txt')
ssh_handler(server, command=mycmd)
I was able to implement this solution which was found in other Stackoverflow threads.
https://www.reddit.com/r/learnpython/comments/60taz7/execute_sudo_su_and_input_password_with_paramiko/df94q7s/
The solution for me was to use invoke_shell() when requiring the use of commands with sudo.
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)
def exec_command(self, command, bufsize=-1):
#print "Executing Command: "+command
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
When executing a command in paramiko, it always resets the session when you run exec_command.
I want to able to execute sudo or su and still have those privileges when I run another exec_command.
Another example would be trying to exec_command("cd /") and then run exec_command again and have it be in the root directory. I know you can do something like exec_command("cd /; ls -l"), but I need to do it in separate function calls.
Non-Interactive use cases
This is a non-interactive example... it sends cd tmp, ls and then exit.
import sys
sys.stderr = open('/dev/null') # Silence silly warnings from paramiko
import paramiko as pm
sys.stderr = sys.__stderr__
import os
class AllowAllKeys(pm.MissingHostKeyPolicy):
def missing_host_key(self, client, hostname, key):
return
HOST = '127.0.0.1'
USER = ''
PASSWORD = ''
client = pm.SSHClient()
client.load_system_host_keys()
client.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
client.set_missing_host_key_policy(AllowAllKeys())
client.connect(HOST, username=USER, 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()
Interactive use cases
If you have an interactive ssh use case, paramiko can handle it... I personally would drive interactive ssh sessions with scrapli.
Listing all the ways I can think of to use paramiko interactively:
See nagabhushan's answer which uses paramiko interactively
By default, ansible paramiko usage is configurable
By default, exscript ssh uses paramiko
By default, netmiko ssh uses paramiko
By default, scrapli ssh uses paramiko
I might have missed some libraries that use paramiko, but it should be clear that paramiko is used quite extensively by python libraries that control ssh sessions.
Try creating a command string separated by \n character. It worked for me.
For. e.g. ssh.exec_command("command_1 \n command_2 \n command_3")
Strictly speaking, you can't. According to the ssh spec:
A session is a remote execution of a program. The program may be a
shell, an application, a system command, or some built-in subsystem.
This means that, once the command has executed, the session is finished. You cannot execute multiple commands in one session. What you CAN do, however, is starting a remote shell (== one command), and interact with that shell through stdin etc... (think of executing a python script vs. running the interactive interpreter)
You can do that by invoking shell on the client and sending commands. Please refer here
The page has code for python 3.5. I have modified the code a bit to work for pythin 2.7. Adding code here for reference
import threading, paramiko
strdata=''
fulldata=''
class ssh:
shell = None
client = None
transport = None
def __init__(self, address, username, password):
print("Connecting to server on ip", str(address) + ".")
self.client = paramiko.client.SSHClient()
self.client.set_missing_host_key_policy(paramiko.client.AutoAddPolicy())
self.client.connect(address, username=username, password=password, look_for_keys=False)
self.transport = paramiko.Transport((address, 22))
self.transport.connect(username=username, password=password)
thread = threading.Thread(target=self.process)
thread.daemon = True
thread.start()
def close_connection(self):
if(self.client != None):
self.client.close()
self.transport.close()
def open_shell(self):
self.shell = self.client.invoke_shell()
def send_shell(self, command):
if(self.shell):
self.shell.send(command + "\n")
else:
print("Shell not opened.")
def process(self):
global strdata, fulldata
while True:
# Print data when available
if self.shell is not None and self.shell.recv_ready():
alldata = self.shell.recv(1024)
while self.shell.recv_ready():
alldata += self.shell.recv(1024)
strdata = strdata + str(alldata)
fulldata = fulldata + str(alldata)
strdata = self.print_lines(strdata) # print all received data except last line
def print_lines(self, data):
last_line = data
if '\n' in data:
lines = data.splitlines()
for i in range(0, len(lines)-1):
print(lines[i])
last_line = lines[len(lines) - 1]
if data.endswith('\n'):
print(last_line)
last_line = ''
return last_line
sshUsername = "SSH USERNAME"
sshPassword = "SSH PASSWORD"
sshServer = "SSH SERVER ADDRESS"
connection = ssh(sshServer, sshUsername, sshPassword)
connection.open_shell()
connection.send_shell('cmd1')
connection.send_shell('cmd2')
connection.send_shell('cmd3')
time.sleep(10)
print(strdata) # print the last line of received data
print('==========================')
print(fulldata) # This contains the complete data received.
print('==========================')
connection.close_connection()
cmd = 'ls /home/dir'
self.ssh_stdin, self.ssh_stdout, self.ssh_stderr = self.ssh.exec_command(cmd)
print self.ssh_stdout.read()
cmd2 = 'cat /home/dir/test.log'
self.ssh_stdin2, self.ssh_stdout2, self.ssh_stderr2 = self.ssh.exec_command(cmd2)
print self.ssh_stdout2.read()
You can run multiple command using the below technique. Use semicolon to separate the Linux commands
Eg:
chan.exec_command("date;ls;free -m")
If you wish each command to have an effect on the next command you should use:
stdin, stdout, stderr = client.exec_command("command1;command2;command3")
but in some cases, I found that when ";" doesn't work, using "&&" does work.
stdin, stdout, stderr = client.exec_command("command1 && command2 && command3")
You can execute an entire BASH script file for better use, here is the code for that:
import paramiko
hostname = "192.168.1.101"
username = "test"
password = "abc123"
# initialize the SSH client
client = paramiko.SSHClient()
# add to known hosts
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
client.connect(hostname=hostname, username=username, password=password)
except:
print("[!] Cannot connect to the SSH Server")
exit()
# read the BASH script content from the file
bash_script = open("script.sh").read()
# execute the BASH script
stdin, stdout, stderr = client.exec_command(bash_script)
# read the standard output and print it
print(stdout.read().decode())
# print errors if there are any
err = stderr.read().decode()
if err:
print(err)
# close the connection
client.close()
This will execute the local script.sh file on the remote 192.168.1.101 Linux machine.
script.sh (just an example):
cd Desktop
mkdir test_folder
cd test_folder
echo "$PATH" > path.txt
This tutorial explains this in detail: How to Execute BASH Commands in a Remote Machine in Python.