本文主要介绍 paramiko
的概念及其使用 1’ 2’ 3‘ 4。
本文环境 Centos 7.9
, Python 3.7
, Paramiko 2.7.2
。
Last Updated: 2022 / 9 / 9
paramiko
5 是用 python
语言写的一个模块,遵循 SSH2
协议 (底层使用 cryptography
),支持以加密和认证的方式,进行远程服务器的连接。
由于使用的是 python
这样的能够跨平台运行的语言,所以所有 python
支持的平台,如 Linux
, Solaris
, BSD
, MacOS X
, Windows
等,paramiko
都可以支持,因此,如果需要使用 SSH
从一个平台连接到另外一个平台,进行一系列的操作时,paramiko
是最佳工具之一。
举个常见的例子,现有这样的需求:需要使用 windows
客户端,远程连接到 Linux
服务器,查看上面的日志状态,大家通常使用的方法会是:
telnet
;PUTTY
;WinSCP
;XManager
等;那现在如果需求又增加一条,要从服务器上下载文件,该怎么办?那常用的办法可能会是:
Linux
上安装 FTP
并配置 ;Linux
上安装 Sambe
并配置 ;大家会发现,常见的解决方法都会需要对远程服务器必要的配置,如果远程服务器只有一两台还好说,如果有N台,还需要逐台进行配置,或者需要使用代码进行以上操作时,上面的办法就不太方便了。
使用 paramiko
可以很好的解决以上问题。比起前面的方法,它仅需要在本地上安装相应的软件(python
以及 PyCrypto
),对远程服务器没有配置要求,对于连接多台服务器,进行复杂的连接操作特别有帮助,可以在 Python
代码中直接使用 SSH
协议对远程服务器执行操作,而不是通过 ssh
命令对远程服务器进行操作,比如连接远程服务器、执行命令和上传、下载文件的功能。。
安装 paramiko
有两个先决条件,python
和另外一个名为 PyCrypto
的模块。
通常安装标准的 python
模块,只需要在模块的根目录下运行:
python setup.py build
python setup.py install
或者,
pip install xxx
paramiko
和 PyCrypto
也不例外,唯一麻烦的就是安装 PyCrypto
时,需要 GCC
库编译,如果没有 GCC
库会报错,会导致 PyCrypto
以及 paramiko
无法安装。
如果是离线安装 6,需要先准备好所有相关的依赖包(bcrypt
、cffi
、cryptography
、pycparser
、PyNaCl
、six
),这些依赖包都可以在 https://pypi.org/
上搜到 6。
离线安装顺序很重要,装下一个是基于上一个,大概顺序是:pycparse
-> cffi
(libffi-devel
是前提依赖 7’ 8’ 9’ 10‘ 11) -> bcrypt
-> six
-> pynacl
-> asnlcrypto
-> cryptography
(openssl-devel
是前提依赖 12’ 13‘ 14’ 15’ 16‘ 17) -> paramiko
18。
如果你装的时候包已经有更新的版本了,可以先找一台可以联网的电脑,记录下它从网上下载的文件记录,然后去找对应的包下载下来,拷到无法联网的电脑上随便什么顺序安装即可。
安装完成后可以在终端中输入 python -c "import paramiko"
, 如果没有报错则说明安装成功。
serialization.Encoding.Raw in kex_curve25519.py
, 可能是由于依赖库之一的 cryptography
的版本问题 19。以下以32 位的 windows XP
为例,说明 paramiko
的安装过程:
2.2
以上版本都可以,安装过程略,并假设安装目录是 c:\python
;GCC
,并在 PATH
变量可以找到。windows
版的 GCC
,即 MinGW
,下载地址为 http://sourceforge.net/projects/mingw/
,然后运行下载后的 exe
文件进行网络安装,假设目录为 C:\mingw
,在 PATH
中加入 C:\mingw\bin
,并在 c:\python\lib\distutils
下新建一个名称是 distutils.cfg
的文件,填入:[build]
compiler=mingw32
PyCrypto
,地址是 https://www.dlitz.net/software/pycrypto/
dos
下进入解压缩的目录,运行C:\python\python.exe setup.py build
C:\python\python.exe setup.py install
测试 paramiko
, 运行 python.exe
,在提示符下输入 Import paramiko
。如果没有出现错误提示,说明 paramiko
安装成功
client = paramiko.SSHClient.connect(
hostname,
port=SSH_PORT,
username=None,
password=None,
pkey=None,
key_filename=None,
timeout=None,
allow_agent=True,
look_for_keys=True,
compress=False,
sock=None,
gss_auth=False,
gss_kex=False,
gss_deleg_creds=True,
gss_host=None,
banner_timeout=None,
auth_timeout=None,
gss_trust_dns=True,
passphrase=None,
disabled_algorithms=None,
)
参数 | 含义 |
---|---|
hostname |
连接的目标主机。 |
port=SSH_PORT |
指定端口 20 |
username=None |
验证的用户名 |
password=None |
验证的用户密码 |
pkey=None |
私钥方式用于身份验证 |
key_filename=None |
一个文件名或文件列表,指定私钥文件 |
timeout=None |
可选的 tcp 连接超时时间 |
allow_agent=True |
是否允许连接到 ssh 代理,默认为 True 允许 |
look_for_keys=True |
是否在 ~/.ssh 中搜索私钥文件,默认为 True 允许 |
compress=False |
是否打开压缩 |
ssh.set_missing_host_key_policy()
设置连接的远程主机没有本地主机密钥或 HostKeys
对象时的策略,目前支持三种:
AutoAddPolicy
HostKeys
对象,不依赖load_system_host_key
的配置。即新建立 ssh
连接时不需要再输入 yes
或 no
进行确认;WarningPolicy
python
警告。并接受,功能上和 AutoAddPolicy
类似,但是会提示是新连接;RejectPolicy
load_system_host_key
的配置。此为默认选项;exec_command(
command,
bufsize=-1,
timeout=None,
get_pty=False,
environment=None,
)
参数 | 含义 |
---|---|
command |
可以任意 linux 支持的命令,如一些常用的命令:cp - 复制代码 df - 查看磁盘使用情况 uptime - 显示系统运行时间信息 cat - 显示某文件内容 mv/cp/mkdir/rmdir - 对文件或目录进行操作 /sbin/service/ xxxservice start/stop/restart - 启动、停止、重启某服务netstat -ntl \grep 8080 - 查看 8080 端口的使用情况 nc -zv localhost - 查看所有端口的使用情况 find / -name XXX - 查找某文件 |
实现 SSH
服务端必须继承 ServerInterface
,并实现里面相应的方法。具体代码如下:
import socket
import sys
import threading
import paramiko
host_key = paramiko.RSAKey(filename='private_key.key')
class Server(paramiko.ServerInterface):
def __init__(self):
#执行start_server()方法首先会触发Event,如果返回成功,is_active返回True
self.event = threading.Event()
#当is_active返回True,进入到认证阶段
def check_auth_password(self, username, password):
if (username == 'root') and (password == '123456'):
return paramiko.AUTH_SUCCESSFUL
return paramiko.AUTH_FAILED
#当认证成功,client会请求打开一个Channel
def check_channel_request(self, kind, chanid):
if kind == 'session':
return paramiko.OPEN_SUCCEEDED
#命令行接收ip与port
server = sys.argv[1]
ssh_port = int(sys.argv[2])
#建立socket
try:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #TCP socket
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((server, ssh_port))
sock.listen(100)
print '[+] Listening for connection ...'
client, addr = sock.accept()
except Exception, e:
print '[-] Listen failed: ' + str(e)
sys.exit(1)
print '[+] Got a connection!'
try:
#用sock.accept()返回的socket实例化Transport
bhSession = paramiko.Transport(client)
#添加一个RSA密钥加密会话
bhSession.add_server_key(host_key)
server = Server()
try:
#启动SSH服务端
bhSession.start_server(server=server)
except paramiko.SSHException, x:
print '[-] SSH negotiation failed'
chan = bhSession.accept(20)
print '[+] Authenticated!'
print chan.recv(1024)
chan.send("Welcome to my ssh")
while True:
try:
command = raw_input("Enter command:").strip("\n")
if command != 'exit':
chan.send(command)
print chan.recv(1024) + '\n'
else:
chan.send('exit')
print 'exiting'
bhSession.close()
raise Exception('exit')
except KeyboardInterrupt:
bhSession.close()
except Exception, e:
print '[-] Caught exception: ' + str(e)
try:
bhSession.close()
except:
pass
sys.exit(1)
参考此处 2’ 21‘ 22
ssh = paramiko.SSHClient()
# 实例化SSHClient,新建client对象
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 自动添加策略,保存服务器的主机名和密钥信息进入host_allow列表,此方法必须放在connect方法的前面。
# 如果不添加,那么不再本地know_hosts文件中记录的主机将无法连接
ssh.connect(hostname='192.168.1.1', port=22, username='root', password='123456')
# 调用connect()方法连接SSH服务端,以用户名和密码进行认证
stdin, stdout, stderr = client.exec_command('df -h ')
# stdout 为正确输出,stderr为错误输出,同时是有1个变量有值
# 打开一个Channel并执行命令
print(stdout.read().decode('utf-8'))
# print(stdout.readlines())
# 打印执行结果
client.close()
# 关闭SSHClient
stdin
无法被read()
,它是input
, 而非output
,否则将会报出"File is not open for reading"
23。
以上需要确保被访问的服务器对应用户 .ssh
目录下有authorized_keys
文件,也就是将服务器上生成的公钥文件保存为authorized_keys
。并将私钥文件作为 paramiko
的登陆密钥。
pkey = paramiko.RSAKey.from_private_key_file('/home/super/.ssh/id_rsa', password='12345')
# 指定本地的RSA私钥文件,如果建立密钥对时设置的有密码,password为设定的密码,如无不用指定password参数
ssh = paramiko.SSHClient()
# 建立连接
ssh.connect(hostname='192.168.2.129',
port=22,
username='super',
pkey=pkey)
stdin, stdout, stderr = ssh.exec_command('df -hl')
print(stdout.read().decode())
# 执行命令, 结果放到stdout中,如果有错误将放到stderr中
ssh.close()
# 关闭连接
参考此处 3’ 21
SSHClient
是传统的连接服务器、执行命令、关闭的一个操作,有时候需要登录上服务器执行多个操作,比如执行命令、上传/下载文件,SSHClient
则无法实现,可以通过如下方式来操作:
t = paramiko.Transport(('192.168.2.129', 22))
# 实例化一个trans对象# 实例化一个transport对象
t.connect(username='super', password='super')
# 建立连接
sftp = paramiko.SFTPClient.from_transport(t)
# 实例化一个 sftp对象,指定连接的通道
传输单个文件的方法为 get
或 put
,但每次只能传输一个文件,而不是整个目录。
比如,传输单个文件的示例如下:
t = paramiko.Transport(('192.168.2.129', 22))
# 实例化一个trans对象# 实例化一个transport对象
t.connect(username='super', password='super')
# 建立连接
sftp = paramiko.SFTPClient.from_transport(t)
# 实例化一个 sftp对象,指定连接的通道
sftp.put(localpath='/tmp/11.txt', remotepath='/Desktop/22.txt')
# 发送文件
# 将本地tmp文件夹下的22.txt put到远端Desktop文件夹并保存为22.txt
sftp.get(remotepath='Desktop/22.txt', localpath='tmp/11.txt')
# 下载文件
# 将远端的Desktop文件夹下的22.txt get到本地tmp文件夹并保存为11.txt
t.close()
# 关闭连接
上面的 remotepath
和 localpath
一定是文件的路径,不能是目录路径。
如何传输整个目录?24’ 25’ 26
有两种思路:
get
则采用 connect
方法连接到linux主机,然后通过 send
方法执行 tar
命令将需要传输的整个目录打包,再传输打包后的文件即可,如果是 put
则需在本地打包。
- 缺点
在远端或者本地进行打包或者解压,并且打包会占用临时存储空间,如果是远端打包还需先
SSH
连接 linux主机。
- 优点
不用做目录扫描处理。
get
或 put
的目录及其子目录,然后依次传输每一个文件。
- 优点
不需要
SSH
登陆和打包解压。
- 缺点
需要做目录扫描,但是目录扫描是很简单的,因此我们采用这种方法。
由于要扫描目录,因此先定义一个方法用来对指定目录进行扫描,找出该目录及所有子目录中的所有文件。
那么,怎么扫描目录呢?使用 python
的 os
库的方法吗?肯定是不行的,因为 python
的 os
库的方法都是对本地目录或文件的操作,它是无法操作远程linux
主机上的文件和目录的。
但是 paramiko
的 SFTP
接口提供了操作远端 linux
主机上的文件和目录的方法,只要建立了与远端的SFTP
连接后,就可以执行文件和目录操作。
import paramiko
import stat
t = paramiko.Transport(('192.168.2.129', 22))
t.connect(username='YourUsername', password='YourPassword')
sftp = paramiko.SFTPClient.from_transport(t)
remote_dir = '/Desktop/Downloads/paho-mqtt-1.5.1'
def get_file_list_in_remote_dir(sftp, remote_dir):
file_list = list()
if remote_dir[-1] == '/':
remote_dir = remote_dir[0:-1]
files = sftp.listdir_attr(remote_dir)
for file in files:
filename = remote_dir + '/' + file.filename
if stat.S_ISDIR(file.st_mode):
file_list.extend(get_file_list_in_remote_dir(sftp, filename))
if stat.S_ISREG(file.st_mode):
file_list.append(filename)
return file_list
file_list = get_file_list_in_remote_dir(sftp=sftp, remote_dir=remote_dir)
在上面的方法中,sftp
表示已经建立的 sftp
连接,remote_dir
是要扫描的远端目录。
在扫描目录的时候,使用的 sftp.listdir_attr
方法会列出指定目录下的所有文件或目录,并且还会列出其属性,比如st_size
, st_uid
, st_gid
, st_mode
, st_atime
, st_mtime
。这些属性与 linux
中的 stat
函数返回的属性类似,我们就是根据其中的 st_mode
属性来判断是一个目录还是文件,并且处理 st_mode
的方法(位于 stat
模块中)也是与 linux
中定义的宏一致的。
获取到指定目录下的所有文件之后,传输就比较简单了,依次遍历 get
即可:
import paramiko
import stat
import os
t = paramiko.Transport(('192.168.2.129', 22))
t.connect(username='YourUsername', password='YourPassword')
sftp = paramiko.SFTPClient.from_transport(t)
remote_dir = '/Desktop/Downloads/paho-mqtt-1.5.1'
local_dir = 'D:\\Test'
def get_file_list_in_remote_dir(sftp, remote_dir):
file_list = list()
if remote_dir[-1] == '/':
remote_dir = remote_dir[0:-1]
files = sftp.listdir_attr(remote_dir)
for file in files:
filename = remote_dir + '/' + file.filename
if stat.S_ISDIR(file.st_mode):
file_list.extend(get_file_list_in_remote_dir(sftp, filename))
if stat.S_ISREG(file.st_mode):
file_list.append(filename)
return file_list
def get_dir(sftp, remote_dir, local_dir):
file_list = get_file_list_in_remote_dir(sftp, remote_dir)
for file in file_list:
file_subdir = os.path.dirname(file).split(remote_dir)[-1]
file_subdir = file_subdir.replace('/', '\\')
file_name = os.path.basename(file)
local_filedir = local_dir + file_subdir
local_filename = local_filedir + '\\' + file_name
if not os.path.exists(local_filedir):
os.makedirs(local_filedir)
sftp.get(file, local_filename)
get_dir(sftp, remote_dir, local_dir)
上面方法将 remote_dir
目录中的所有文件都按与远端一致的目录结构 get
到了本地 local_dir
目录中。
下面再来看看 put
,其实与 get
几乎一样,现在扫描本地目录,然后依次遍历文件并 put
到远端 27。
由于是对本地目录做扫描,因此不需要调用 SFTP
中的文件目录处理接口了,直接使用 python
的 os
库即可,代码如下:
import paramiko
import stat
import os
t = paramiko.Transport(('192.168.2.129', 22))
t.connect(username='YourUsername', password='YourPassword')
sftp = paramiko.SFTPClient.from_transport(t)
local_dir = 'D:\\Test'
remote_dir = '/Desktop/Downloads/paho-mqtt-1.5.1'
def get_file_list_in_local_dir(sftp, local_dir):
file_list = list()
files = os.listdir(local_dir)
for file in files:
filename = os.path.join(local_dir, file)
if os.path.isdir(filename):
file_list.extend(get_file_list_in_local_dir(sftp, filename))
else:
file_list.append(filename)
return file_list
def put_dir(sftp, local_dir, remote_dir):
file_list = get_file_list_in_local_dir(sftp, local_dir)
for file in file_list:
file_subdir = os.path.dirname(file).split(local_dir)[-1]
file_subdir = file_subdir.replace('\\', '/')
file_name = os.path.basename(file)
remote_filedir = remote_dir + file_subdir
if remote_filedir.endswith('/'):
remote_filedir = remote_filedir[0:-1]
remote_filename = remote_filedir + '/' + file_name
try:
sftp.stat(remote_filedir)
except:
sftp.mkdir(remote_filedir)
sftp.put(file, remote_filename, confirm=True)
put_dir(sftp, local_dir=local_dir, remote_dir=remote_dir)
exec_command(
command,
bufsize=-1,
timeout=None,
get_pty=False,
environment=None,
)
参数 | 含义 |
---|---|
command |
可以任意 linux 支持的命令,如一些常用的命令:cp - 复制代码 df - 查看磁盘使用情况 uptime - 显示系统运行时间信息 cat - 显示某文件内容 mv/cp/mkdir/rmdir - 对文件或目录进行操作 /sbin/service/ xxxservice start/stop/restart - 启动、停止、重启某服务netstat -ntl \grep 8080 - 查看 8080 端口的使用情况 nc -zv localhost - 查看所有端口的使用情况 find / -name XXX - 查找某文件 |
注意,在 windows
中,sys.stdin
不是一个 socket
或者 file-like
对象,而是一个 PseudoOutputFile
对象,不能被 select
处理。所以上面的脚本不能在 windows
中运行,只能用于 linux
。
import paramiko
import os
import select
import sys
# 建立一个socket
trans = paramiko.Transport(('192.168.2.129', 22))
# 启动一个客户端
trans.start_client()
# 如果使用rsa密钥登录的话
'''
default_key_file = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa')
prikey = paramiko.RSAKey.from_private_key_file(default_key_file)
trans.auth_publickey(username='super', key=prikey)
'''
# 如果使用用户名和密码登录
trans.auth_password(username='super', password='super')
# 打开一个通道
channel = trans.open_session()
# 获取终端
channel.get_pty()
# 激活终端,这样就可以登录到终端了,就和我们用类似于xshell登录系统一样
channel.invoke_shell()
# 下面就可以执行你所有的操作,用select实现
# 对输入终端sys.stdin和 通道进行监控,
# 当用户在终端输入命令后,将命令交给channel通道,这个时候sys.stdin就发生变化,select就可以感知
# channel的发送命令、获取结果过程其实就是一个socket的发送和接受信息的过程
while True:
readlist, writelist, errlist = select.select([channel, sys.stdin,], [], [])
# 如果是用户输入命令了,sys.stdin发生变化
if sys.stdin in readlist:
# 获取输入的内容
input_cmd = sys.stdin.read(1)
# 将命令发送给服务器
channel.sendall(input_cmd)
# 服务器返回了结果,channel通道接受到结果,发生变化 select感知到
if channel in readlist:
# 获取结果
result = channel.recv(1024)
# 断开连接后退出
if len(result) == 0:
print("\r\n**** EOF **** \r\n")
break
# 输出到屏幕
sys.stdout.write(result.decode())
sys.stdout.flush()
# 关闭通道
channel.close()
# 关闭链接
trans.close()
import paramiko
import os
import select
import sys
import tty
import termios
'''
实现一个xshell登录系统的效果,登录到系统就不断输入命令同时返回结果
支持自动补全,直接调用服务器终端
'''
# 建立一个socket
trans = paramiko.Transport(('192.168.2.129', 22))
# 启动一个客户端
trans.start_client()
# 如果使用rsa密钥登录的话
'''
default_key_file = os.path.join(os.environ['HOME'], '.ssh', 'id_rsa')
prikey = paramiko.RSAKey.from_private_key_file(default_key_file)
trans.auth_publickey(username='super', key=prikey)
'''
# 如果使用用户名和密码登录
trans.auth_password(username='super', password='super')
# 打开一个通道
channel = trans.open_session()
# 获取终端
channel.get_pty()
# 激活终端,这样就可以登录到终端了,就和我们用类似于xshell登录系统一样
channel.invoke_shell()
# 获取原操作终端属性
oldtty = termios.tcgetattr(sys.stdin)
try:
# 将现在的操作终端属性设置为服务器上的原生终端属性,可以支持tab了
tty.setraw(sys.stdin)
channel.settimeout(0)
while True:
readlist, writelist, errlist = select.select([channel, sys.stdin,], [], [])
# 如果是用户输入命令了,sys.stdin发生变化
if sys.stdin in readlist:
# 获取输入的内容,输入一个字符发送1个字符
input_cmd = sys.stdin.read(1)
# 将命令发送给服务器
channel.sendall(input_cmd)
# 服务器返回了结果,channel通道接受到结果,发生变化 select感知到
if channel in readlist:
# 获取结果
result = channel.recv(1024)
# 断开连接后退出
if len(result) == 0:
print("\r\n**** EOF **** \r\n")
break
# 输出到屏幕
sys.stdout.write(result.decode())
sys.stdout.flush()
finally:
# 执行完后将现在的终端属性恢复为原操作终端属性
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)
# 关闭通道
channel.close()
# 关闭链接
trans.close()
t = paramiko.Transport(('192.168.2.129', 22))
# 实例化一个transport对象
t.connect(username='super', password='super')
ssh = paramiko.SSHClient()
ssh._transport = t
# 将sshclient的对象ssh的transport指定为以上的t
stdin, stdout, stderr = ssh.exec_command('df -hl')
print(stdout.read().decode())
# 执行命令,和传统方法一样
t.close()
# 关闭连接
pkey = paramiko.RSAKey.from_private_key_file('/home/super/.ssh/id_rsa', password='12345')
# 指定本地的RSA私钥文件,如果建立密钥对时设置的有密码,password为设定的密码,如无不用指定password参数
# 建立连接
t = paramiko.Transport(('192.168.2.129', 22))
t.connect(username='super', pkey=pkey)
ssh = paramiko.SSHClient()
ssh._transport = t
# 将sshclient的对象的transport指定为以上的trans
stdin, stdout, stderr = ssh.exec_command('df -hl')
print(stdout.read().decode())
# 执行命令,和传统方法一样
t.close()
# 关闭连接
t = paramiko.Transport((“主机”,”端口”))
# 实例化一个传输对象
t.connect(username = “用户名”, password = “口令”)
# 建立连接。如果连接远程主机需要提供密钥,上面第二行代码可改成:
# t.connect(username = “用户名”, password = “口令”, hostkey=”密钥”)
sftp = paramiko.SFTPClient.from_transport(transport)
# 将实例Transport作为参数传入SFTPClient中
sftp.put(r'E:\Users\Desktop\test.txt','/opt/test1.txt')
# 将本地桌面test.txt文件上传至虚拟机opt目录下
sftp.get('/opt/test2.txt',r'E:\Users\Desktop\test2.txt')
# 将虚拟机opt目录下test2.txt下载到本地桌面
t.close()
#关闭连接
f’ ‘:格式化
r’ ‘:去除转义
b’ ‘:指定为字节类型
u’ ':指定为Unicode编码
#!/usr/bin/env python3
import sys
import paramiko
import threading
import os
def remote_comm(host, pwd, command):
'''
创建函数实现远程连接主机、服务器密码以及在远程主机上执行的命令的功能
:param host:
:param pwd:
:param command:
:return:
'''
ssh = paramiko.SSHClient()
# 创建用于连接ssh服务器的实例
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 设置自动添加主机密钥
try:
ssh.connect(hostname=host, username='root', password=pwd)
# 连接ssh服务器,添加连接的主机、用户名、密码填好,捕获异常,有异常则跳出函数
except:
return
stdin, stdout, stderr = ssh.exec_command(command)
# 在ssh服务器上执行指定命令,返回3项类文件对象,分别是,输入、输出、错误
out = stdout.read() # 读取输出
error = stderr.read() # 读取错误
if out: # 如果有输出
print('[%s] OUT:\n%s' % (host, out.decode('utf8')))
# 打印主机输出内容
if error: # 如果有错误
print('[%s] ERROR:\n%s' % (host, error.decode('utf8')))
# 打印主机错误信息
ssh.close() # 程序结束
if __name__ == '__main__':
if len(sys.argv) != 3:
# 设定sys.argv长度,确保remote_comm函数中参数数量
print('Usage: %s ipaddr_file "command"' % sys.argv[0])
exit(1)
if not os.path.isfile(sys.argv[1]):
# 判断命令行上输入如果不是文件,确保输入的是文件
print('No such file:', sys.argv[1])
exit(2)
fname = sys.argv[1]
# fname为存储远程主机ip的文件,用sys.argv方法,可以在执行脚本时再输入文件名,更为灵活
command = sys.argv[2]
# command为在远程主机上执行的命令,用sys.argv方法,可以在执行脚本时再输入相应命令,command为remote_comm函数第三个参数
# 通过getpass输入远程服务器密码,pwd为remote_comm函数第二个参数
# pwd = getpass.getpass()
pwd='Taren1.bgsn'
with open(fname) as fobj:
# 打开存有远程主机ip的文件
ips = [line.strip() for line in fobj]
# 将遍历文件将ip以列表形式存入ips,line.strip()可以去掉每行ip后
for ip in ips:
# 循环遍历列表,获取ip地址,ip为remote_comm函数第一个参数
# 将读取到的ip地址作为remote_comm函数实际参数传递给函数,ips中有几个ip地址循环几次
t = threading.Thread(target=remote_comm, args=(ip, pwd, command))
# 创建多线程
t.start()
# 启用多线程
详情需参考此处 2
python使用paramiko实现ssh的功能详解 ↩︎
paramiko模块怎么在Python项目中使用 ↩︎ ↩︎ ↩︎
paramiko的安装与使用 ↩︎ ↩︎
paramiko 远程连接ssh ↩︎
paramiko ↩︎
windows下python3.7离线安装paramiko库全文件,亲测有用,太折腾人了 ↩︎ ↩︎
Installing cffi fails with c/_cffi_backend.c:15:17: fatal error: ffi.h: No such file or directory ↩︎
linux系统中离线安装python3.7过程记录 ↩︎
[小技巧] Linux 里快速安装缺少的库 ↩︎
Libffi-devel Download for Linux (eopkg, rpm, xbps) ↩︎
关于在centos下安装python3.7.0以上版本时报错ModuleNotFoundError: No module named ‘_ctypes‘的解决办法 ↩︎
How to fix: fatal error: openssl/opensslv.h: No such file or directory in RedHat 7 ↩︎
Linux Ubuntu openssl离线源码安装、升级版本 ↩︎
Frequently asked questions ↩︎
Linux中的 openssl/opensslv.h找不到的问题解决 ↩︎
Openssl-devel Download for Linux (eopkg, pkg, rpm, xbps) ↩︎
Welcome to OpenSSL! ↩︎
Paramiko Docs ↩︎
paramiko.SSHClient.connect raises unknown exception ↩︎
IP地址、MAC地址以及端口号 ↩︎
paramiko模块使用方法(十二) ↩︎ ↩︎
^paramiko连接方式 ↩︎
Can’t get stderr with Paramiko ↩︎
使用paramiko的SFTP get或put整个目录 ↩︎
Python3-paramiko-SFTP上传文件夹到多台远程服务器 ↩︎
python之paramiko文件夹远程上传 ↩︎
paramiko怎么判断远程目录是否存在? ↩︎