一、ssh连接、执行命令、打印输出
import paramiko
# 创建SSH客户端
client = paramiko.SSHClient()
# 自动添加主机名和密钥到本地的known_hosts文件
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接到远程主机
client.connect('远程主机IP', username='用户名', password='密码')
# 执行命令
stdin, stdout, stderr = client.exec_command('要执行的命令')
# 打印命令的输出
print(stdout.read().decode())
# 封装成函数时可以:
# return stdout.read().decode('utf-8', errors='ignore'), stderr.read().decode('utf-8', errors='ignore'),
注意:
exec_command每次通过开一个新的Channel来执行传输的命令,因此只能执行一条命令,也就是说第一行执行exec_command(“cd xxx”),第二行想在第一行cd的基础上执行exec_command(tar -xzvf xxx)是不行的,因为每次执行完都会回到根目录,所以无法第一次cd切换路径,第二次去该路径进行操作
解决方法:在exec_command中一次执行多个命令,把要执行的命令之间用 \n 分开,且最后一个命令后不要带\n
import paramiko
# cd到一个目录后进行压缩包解压
stdin, stdout, stderr = client.exec_command("cd /hone/documents\n tar -xzvf abc.tar.gz")
# 如果涉及到入参拼接,\n怎么放
# cd进去,再cd进解压后的文件夹,最后执行安装
file_path = /home/documents
folder= abc
stdin, stdout, stderr = client.exec_command("cd " + file_path + "\n cd " + abc + "\n bash install.sh")
二、如何保持shell窗口一直连接状态
exec_command每次执行后都会退出当前的shell
如果想在当前的shell下根据输出提示持续输出(比如密码卸载、ftp传输文件、vim等),此时就需要使用invoke_shell
import paramiko
import time
# 创建连接、添加密钥、远程的操作见上面的介绍,此处省略...
# 封装一个ftp传输文件的函数
def ftp_trans_file():
ftp_file_path = "/home/user/文件集"
ftp_file_name = "123.txt"
ftp_host = 10.xx.xx.xx
ftp_username = aaa
ftp_password = 123456
shell = client.invoke_shell()
shell.send("cd " + ftp_file_path + "\n ftp\n") # cd到文件目录下,输入ftp,第一个\n用于连续执行两条命令,第二个\n是用于输入ftp后换行(模拟按下enter键)
time.sleep(1)
shell.send("open " + ftp_host + "\n") # 打开文件传输ip,并按回车
time.sleep(1)
shell.send(ftp_username + "\n") # 输入用户名
time.sleep(1)
shell.send(ftp_password + "\n") # 输入密码
time.sleep(1)
shell.send("put " + ftp_file_name + "\n") # 输入密码
time.sleep(1)
data = shell.recv(9999).decode('utf-8') # 获取传输文件前后所有的提示语
shell.send('exit\n') # 退出
shell.close() # 关闭
return data
扩展:
shell模拟enter键:shell.send(“\n”)
shell模拟esc键:shell.sned(“\x1b”)
三、补充
1、exec_command与invoke_shell的区别
invoke_shell使用的是SSH shell channel的方式执行,具备持久化能力,类似于MobaXterm,
shell命令用exec_command
shell脚本用invoke_shell
2、使用invoke_shell的情况下,获取值,处理后再给值(密码卸载)
将shell.recv放在中间,上面的shell.recv放在了最后,是接收了所有消息
import paramiko
import time
# 创建连接、添加密钥、远程的操作见上面的介绍,此处省略...
# 封装一个ftp传输文件的函数
def ftp_trans_file():
shell = client.invoke_shell()
shell.send("cd /usr/local/bin\n ./unins\n") # cd到卸载目录下,输入./unins,第一个\n用于连续执行两条命令,第二个\n是用于输入./unins后换行(模拟按下enter键)
time.sleep(2)
data = shell.recv(9999).decode('utf-8') # 获取系统返回的那一行的信息
text = data.split()[-1] # 括号内不给值表示默认从空格、换行进行切割
print(text) # 获取到了卸载码
# 以下应该要把卸载码取出后回win上进行生成执行码,然后将执行码继续输入执行卸载,省略...
shell.send('exit\n') # 退出
shell.close() # 关闭
return data
文章出处登录后可见!
已经登录?立即刷新