import paramiko
ssh =paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='test.com',username='test',password='test123')
srcpath = ('/tmp/test/')
destpath = ('/tmp/file/')
transfer=ssh.open_sftp()
stdin, stdout, stderr = ssh.exec_command('cd /tmp/test/; ls -1t *txt* | head -1')
out = stdout.read().splitlines()
print out
error = stderr.read().splitlines()
print error
transfer.close()
ssh.close()
Above is my code, i tried to retrieve the latest directory on remote server. I am facing below error.
Error:
['bash: head: command not found']
is there any other way to retrieve latest directory ?
You actually don't need "head" nor "tail", just access the last line from python as follows.
This is your code little edited to catch the last line as last_line:
import paramiko
ssh =paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='test.com',username='test',password='test123')
srcpath = ('/tmp/test/')
destpath = ('/tmp/file/')
transfer=ssh.open_sftp()
stdin, stdout, stderr = ssh.exec_command('cd /tmp/test/; ls -1t *txt*')
out = stdout.read().splitlines()
last_line = out[-1] ## takes out the last line without need for tail command
print out
print last_line
error = stderr.read().splitlines()
print error
transfer.close()
ssh.close()
Related
This question already has an answer here:
Paramiko error when trying to edit file: "sudo: no tty present and no askpass program specified"
(1 answer)
Closed 2 years ago.
I have verified the existing thread but unable to get the exact reason and resolution of this problem.
PROBLEM: 'sudo: no tty present and no askpass program specified'
When code is as follows:
str_command_to_exec += str(each_cmd).strip() + "\n"
# Now execute the command
stdin, stdout, stderr = self.client.exec_command('sudo -S ls')
Below are the possible solutions that I have applied but still no progress.
Sol: Append the Password to command.
'sudo: no tty present and no askpass program specified. bash: line 1: : command not found'
Sol2: stdin, stdout, stderr = client.exec_command(command, get_pty=True)
More than 30 seconds still no idea whether control passed from exec_command(...).
Sol3: self.client.get_pty()
Unable to setup the connection.
Sol4:
stdin, stdout, stderr = self.client.exec_command('sudo -S ls')
stdin.write('\n')
stdin.flush()
time.sleep(2)
Unable to do the same for sudo command 'stdin, stdout, stderr = self.client.exec_command('sudo -S info')' cause the same PROBLEM.
Can someone please point me if there is any solution to handle Sudo commands or workarounds?
I am able to get the solution for this problem.
I have used send(..) instead of execute_command(...).
SETUP:
self.client = paramiko.client.SSHClient()
self.client.set_missing_host_key_policy(paramiko.client.AutoAddPolicy())
self.client.connect(hostname=self.str_host_name, port=22,
username=self.str_user_name, password=self.str_user_pass)
self.transport = paramiko.Transport(self.str_host_name, 22)
self.transport.connect(username=self.str_user_name, password=self.str_user_pass)
EXECUTION:
if self.shell:
self.shell.send(str_sudo_command + "\n")
if self.shell is not None:
time.sleep(2)
self.str_sudo_command_result += str(self.shell.recv(1024).decode('utf-8'))
self.str_sudo_command_result = str(self.str_sudo_command_result).strip()
self.str_sudo_command_result = self.str_sudo_command_result.splitlines()
if len(self.str_sudo_command_result) > 0:
if "[sudo] password for " in self.str_sudo_command_result[-1]:
self.str_sudo_command_result = ""
self.shell.send(self.str_user_pass + "\n")
time.sleep(2)
else:
while True:
result = str(self.str_sudo_command_result)
result = result.splitlines()
time.sleep(2)
if self.str_result_end_line not in result[-1]:
while self.shell.recv_ready():
self.str_sudo_command_result += str(self.shell.recv(9999).decode('utf-8'))
else:
break
Suggestions and corrections are welcomed.
I'm trying to run various linux commands via python's subprocess and ssh. I'd like to be able to run the command and check the stderr and stdout lengths to determine if the command was successful or not. For example if there's no error it was successful. The problem is that after the initial connection all the output is going to stdout.
I did try using paramiko but kept getting unreliable authentication behaviour. This approach seems more robust, if I could just get it to work.
import subprocess
import os
import pty
from select import select
class open_ssh_helper(object):
def __init__(self, host="127.0.0.1", user="root"):
self.host = host
self.user = user
self.cmd = ['ssh',
user +'#'+host,
"-o", "StrictHostKeyChecking=no",
"-o", "UserKnownHostsFile=/dev/null"]
self.prompt = '~#'
self.error = ''
self.output = ''
self.mtty_stdin, self.stty_stdin = pty.openpty()
self.mtty_stdout, self.stty_stdout = pty.openpty()
self.mtty_stderr, self.stty_stderr = pty.openpty()
self.ssh = subprocess.Popen(self.cmd,
shell=False,
stdin=self.stty_stdin,
stdout=self.stty_stdout,
stderr=self.stty_stderr)
self._read_stderr()
self._read_stdout()
def _reader(self, read_pty):
char = ""
buf = ""
while True:
rs, ws, es = select([read_pty], [], [], 0.5)
if read_pty in rs:
char = os.read(rs[0], 1)
buf += char
else:
break
return buf
def _read_stderr(self):
self.error = self._reader(self.mtty_stderr)
def _read_stdout(self):
self.output = self._reader(self.mtty_stdout)
def execute(self, command):
os.write(self.mtty_stdin, command)
self._read_stderr()
self._read_stdout()
if __name__=='__main__':
ss = open_ssh_helper('10.201.202.236', 'root')
print "Error: \t\t: " + ss.error
print "Output: \t: " + ss.output
ss.execute("cat /not/a/file\n")
print "Error: \t\t: " + ss.error
print "Output: \t: " + ss.output
Which outputs something like:
Error: : Warning: Permanently added '10.201.202.236' (ECDSA) to the list of known hosts.
Debian GNU/Linux 8
BeagleBoard.org Debian Image xxxx-xx-xx
Support/FAQ: http://elinux.org/Beagleboard:BeagleBoneBlack_Debian
Output: : Last login: Thu Oct 5 07:32:06 2017 from 10.201.203.29
root#beaglebone:~#
Error: :
Output: : cat /not/a/file
cat: /not/a/file: No such file or directory
root#beaglebone:~#
My hope was that the line cat: /not/a/file: No such file or directory would be printed as the error line above it. However it seems that for some reason the stdout is printing both the output and the error.
ssh pulls back both stdout and stderr on the remote system as a single stream so they both come through on the ssh stdout.
If you want to separate the two streams on the remote system you will have to do that by redirecting one or both of them to a remote file and then reading the files. Or less reliably but possibly easier, you could redirect stderr through a filter that puts something like 'STDERR:' on the start of each line and split the streams again that way.
Below I am connected to a remote machine and reading (cat) a file. The output is something like this:
AIMS_PASS=wreretet
ASAPMSTR_PASS=dfdgdg
CREP_PASS=gfhfh
DSS_PASS=dgfhhfh
ELS_PASS=Rdgdh
EXTAPI_PASS=qadgdbbc
I need the words before _PASS like AIMS, ASAPMSTR, CREP,..But these are output from the remote server. I know cut -d _ -f 1 would work if the data is local. How do I apply this command on the output from remote server. Specifically inside the if loop.
pswd = re.compile(r'\w_PASS\W')
if conn is None:
print machine +" " + "Successfully Authenticated\n"
stdin, stdout, stderr = ssh.exec_command("""python -c 'import os; \
print os.path.isfile("/a/etc/portal/db/secrets/db.shared") \
'""")
ret_val = stdout.read()
if ret_val:
print "db.shared file is there!"
stdin, stdout, stderr = ssh.exec_command("cat /a/etc/portal/db/secrets/db.shared")
data = stdout.read()
pswd_line = pswd.findall(data)
if pswd_line:
print data
<SOMETHING WHICH JUST GIVES ME THE WORD BEFORE '_PASS'>
#stdin, stdout, stderr = ssh.exec_command("cut -d _ -f 1")
#print stdout.read()
ssh.close()
break
else:
stdin, stdout, stderr = ssh.exec_command("exit")
If I understand correctly what your data variable holds:
x = "AIMS_PASS=wreretet\nASAPMSTR_PASS=dfdgdg"
[line.split('_PASS')[0] for line in x.split('\n')]
>>> ['AIMS', 'ASAPMSTR']
I use the Python split method to first split by new line, then split by _PASS and then take the first element.
I am writing a python script with the paramiko module. It ssh's into a remote hosts, runs script, and automates/answers interactive prompts. It works pretty good so far. For the output, I would like to have both stdin, stdout, stderr streams pointing together(to stdout) so I can see them in stdout.readlines(). But as it is now, I am not seeing the stdin.write() calls I placed in the script. How can I get stdin.write() included in the output?
import paramiko
bar = "5555"
foofilename = ""
cont = "Y"
fname = '/foobar/file.txt'
ssh=paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect( host, port=22, username=uname, password=pword)
stdin, stdout, stderr=ssh.exec_command("script.sh")
stdin.write(bar+"\n")
stdin.flush()
stdin.write(foofilename+"\n")
stdin.flush()
stdin.write(cont+"\n")
stdin.flush()
stdin.write(fname+"\n")
stdin.flush()
output = stdout.readlines()
for line in output:
print line.split("\n")
import paramiko
import os
import sys
ssh = paramiko.SSHClient()
paramiko.util.log_to_file('U:\\Temp\\paramiko.log')
ssh.load_system_host_keys()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('172.18.24.234','/TestBTEC/',22,'btectest','M3j0Stanf0rd')
stdin, stdout, stderr = ssh.exec_command("mkdir abc")
stdout.readlines()
This is obviously throwing back errors. What is the proper way to set the home directory on the remote server for user btectest
Instead of setting you can also specify parent directory as userprofile as below
import os
abc_dir = os.path.join('%UserProfile%','abc')
cmd = "mkdir %s" % abc_dir
stdin, stdout, stderr = ssh.exec_command(cmd)
The parameters you are passing to SSHCient.connect() are incorrect (at least for paramiko 1.6+). Your connect() call should look like this:
ssh.connect('172.18.24.234', username='btectest', password='...')
or if you explicitly include the port:
ssh.connect('172.18.24.234', 22, 'btectest', '...')
Once connected, you should already be in the home directory of the user "btectest", as can be seen with this:
stdin, stdout, stderr = ssh.exec_command("pwd")
stdout.readlines()