首页 > 技术文章 > python 批量ssh并执行命令

chengxuyonghu 2020-09-09 10:39 原文

1、安装paramiko模块

    pip install paramiko

   可以修改ssh连接超时时间,windows下路径:在安装路径Python\Python36\Lib\site-packages\paramiko\transport.py,修改self.banner_timeout = 60(设置ssh超时为60秒)

2、利用python进行ssh

            

import paramiko,getpass  #getpass是隐藏密码

def ssh_connect(password):
    host_ip = '192.168.0.150'
    user_name = 'root'
    host_port ='22'

    # 待执行的命令
    sed_command = "sed -i 's/123/abc/g' /root/test/test.txt"
    ls_command = "ls /root/test/"

    # 注意:依次执行多条命令时,命令之间用分号隔开
    command = sed_command+";"+ls_command
# SSH远程连接
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) #指定当对方主机没有本机公钥的情况时应该怎么办AutoAddPolicy表示自动在对方主机保存下本机的秘钥 ssh.connect(host_ip, host_port, user_name, password) # 执行命令并获取执行结果 stdin, stdout, stderr = ssh.exec_command(command) out = stdout.readlines() err = stderr.readlines()
#关闭连接 ssh.close()
return out,err if __name__ == '__main__': pwd = getpass.getpass("请输入密码:")

   #有了密码,开始调用函数

result
= ssh_connect(pwd)
print(result)

 

 

python中的paramiko模块是用来实现ssh连接到远程服务器上的库,在进行连接的时候,可以用来执行命令,也可以用来上传文件。

1、得到一个连接的对象

在进行连接的时候,可以使用如下的代码:

 

def connect(host):
  ssh = paramiko.SSHClient()
  ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  try:
    #ssh.connect(host,username='root',allow_agent=True,look_for_keys=True)

ssh.connect(host,username='root',password='root',allow_agent=True)
return ssh except: return None

 

在connect函数中,参数是一个主机的IP地址或者是主机名称,在执行这个方法之后,如果成功的连接到服务器,那么就会返回一个sshclient对象。

第一步是建立一个SSHClient的对象,然后设置ssh客户端允许连接不在know_host文件中的机器,然后就尝试连接服务器。

在连接服务器的时候,可以使用两种方式:

 

(1)方式是使用秘钥的方式,也就是参数look_for_keys

 

(2)用设置密码寻找,也可以直接使用密码的方式,也就是直接使用参数password,从而最后返回一个连接的对象。

 

2、 获取设置的命令

在进行paramiko连接之后,那么必须要得到需要执行的命令,如下代码所示:

def command(args,outpath):
  
  cmd = '%s %s' % (outpath,args)
  return cmd

 

在参数中,一个是args,一个outpath,args表示命令的参数,而outpath表示为可执行文件的路径,例如/usr/bin/ls -l。在其中outpath也就是/usr/bin/ls ,而参数为-l

这个方法主要是用来组合命令,将分开的参数作为命令的一部分进行组装。

3、 执行命令

在连接过后,可以进行直接执行命令,那么就有了如下的函数:

def exec_commands(conn,cmd):
  
  stdin,stdout,stderr = conn.exec_command(cmd)
  results=stdout.read()
  return results

 

在此函数中,传入的参数一个为连接的对象conn,一个为需要执行的命令cmd,最后得到执行的结果,也就是stdout.read(),最后返回得到的结果

 

4、 上传文件

在使用连接对象的时候,也可以直接进行上传相关的文件,如下函数:

def copy_moddule(conn,inpath,outpath):
  
  ftp = conn.open_sftp()
  ftp.put(inpath,outpath)
  ftp.close()
  return outpath

 

此函数的主要参数为,一个是连接对象conn,一个是上传的文件名称,一个上传之后的文件名称,在此必须写入完整的文件名称包括路径。

做法主要是打开一个sftp对象,然后使用put方法进行上传文件,最后关闭sftp连接,最后返回一个上传的文件名称的完整路径

5、 执行命令得到结果

最后就是,执行命令,得到返回的结果,如下代码:

def excutor(host,outpath,args):
  conn = connect(host)
  if not conn:
    return [host,None]

#调用函数 exec_commands(conn,
'chmod +x %s' % outpath)

#调用函数,获得命令参数及其路径 cmd
=command(args,outpath)

#调用函数执行命令 result
= exec_commands(conn,cmd)
print '%r' % result result = json.loads(result) return [host,result]

 

首先,进行连接服务器,得到一个连接对象,如果连接不成功,那么返回主机名和None,表示没有连接成功,如果连接成功,那么修改文件的执行权限,从而可以执行文件,然后得到执行的命令,最后,进行执行命令,得到结果,将结果用json格式表示返回,从而结果能得到一个美观的json格式,最后和主机名一起返回相关的信息

 

6、 测试代码

测试代码如下:

if __name__ == '__main__':
  print json.dumps(excutor('192.168.1.165','ls',' -l'),indent=4,sort_keys=True)
  print copy_module(connect('192.168.1.165'),'kel.txt','/root/kel.1.txt')
  exec_commands(connect('192.168.1.165'),'chmod +x %s' % '/root/kel.1.txt')

第一步测试命令执行,第二步测试上传文件,第三部测试修改上传文件的权限。

完整代码如下:

 

 

#!/usr/bin/env python
import json
import paramiko

def connect(host):
  
  ssh = paramiko.SSHClient()
  ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
  try:
    #ssh.connect(host,username='root',allow_agent=True,look_for_keys=True)
    ssh.connect(host,username='root',password='root',allow_agent=True)
    return ssh
  except:
    return None

def command(args,outpath):
  
  cmd = '%s %s' % (outpath,args)
  return cmd

def exec_commands(conn,cmd):
  
  stdin,stdout,stderr = conn.exec_command(cmd)
  results=stdout.read()
  return results

def excutor(host,outpath,args):
  conn = connect(host)
  if not conn:
    return [host,None]
  #exec_commands(conn,'chmod +x %s' % outpath)
  cmd =command(args,outpath)
  result = exec_commands(conn,cmd)
  result = json.dumps(result)
  return [host,result]

def copy_module(conn,inpath,outpath):
    
    ftp = conn.open_sftp()
    ftp.put(inpath,outpath)
    ftp.close()
    return outpath


if __name__ == '__main__':
    print json.dumps(excutor('192.168.1.165','ls',' -l'),indent=4,sort_keys=True)
    print copy_module(connect('192.168.1.165'),'kel.txt','/root/kel.1.txt')
    exec_commands(connect('192.168.1.165'),'chmod +x %s' % '/root/kel.1.txt')

Python实现ssh批量登录并执行命令

 

pexpect模块版本

 

#!/usr/bin/env python 
# -*- coding: utf-8 -*- 
 
import pexpect 
 
def ssh_cmd(ip, passwd, cmd): 
  ret = -1 
  ssh = pexpect.spawn('ssh root@%s "%s"' % (ip, cmd)) 
  try: 
    i = ssh.expect(['password:', 'continue connecting (yes/no)?'], timeout=5) 
    if i == 0 : 
      ssh.sendline(passwd) 
    elif i == 1: 
      ssh.sendline('yes\n') 
      ssh.expect('password: ') 
      ssh.sendline(passwd) 
    ssh.sendline(cmd) 
    r = ssh.read()
  print r 
    ret = 0 
  except pexpect.EOF: 
    print "EOF" 
    ssh.close() 
    ret = -1 
  except pexpect.TIMEOUT: 
    print "TIMEOUT"

ssh.close() ret = -2 return ret

 

aramiko模块版本

#-*- coding: utf-8 -*- 
#!/usr/bin/python  
import paramiko 
import threading 
def ssh2(ip,username,passwd,cmd): 
  try: 
    ssh = paramiko.SSHClient() 
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 
    ssh.connect(ip,22,username,passwd,timeout=5) 
    for m in cmd: 
      stdin, stdout, stderr = ssh.exec_command(m) 
      #stdin.write("Y")  #简单交互,输入 ‘Y'  
      out = stdout.readlines() 
      #屏幕输出 
      for o in out: 
        print o, 
    print '%s\tOK\n'%(ip) 
    ssh.close() 
  except : 
    print '%s\tError\n'%(ip) 
if __name__=='__main__': 
  cmd = ['cal','echo hello!']#你要执行的命令列表 
  username = "" #用户名 
  passwd = ""  #密码 
  threads = []  #多线程 
  print "Begin......" 
  for i in range(1,254): 
    ip = '192.168.1.'+str(i) 

#开启多线程执行命令 a
=threading.Thread(target=ssh2,args=
(ip,username,passwd,cmd)) a.start()

 

python 切换root 执行命令的方法

import paramiko
def create_user(root_pwd,username,password):
  
  result = []
ssh
= paramiko.SSHClient()
#把要连接的机器添加到known_hosts文件中 ssh.load_system_host_keys() ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect( hostname
= settings.HOST, port = settings.PORT, username = settings.USERNAME, password = settings.PASSWORD, timeout = 60, ) sc = ssh.invoke_shell()
#定义函数
def exe_cmd(cmd,t=0.1): sc.send(cmd) sc.send("\n") time.sleep(t) resp = sc.recv(9999).decode("utf8") #print "cmd='%s',echo='%s'\n"%(cmd,resp) return resp #切换root账号 resp = exe_cmd("su root",t=1) if resp.endswith(u"密码:"): resp = exe_cmd(root_pwd) #创建用户 cmd_create_user = "useradd {username} -d /home/{username}".format( username = username, ) exe_cmd(cmd_create_user) #修改密码 cmd_change_user_pwd = """echo "{password}" | passwd --stdin {username}""".format( username = username, password = password, ) exe_cmd(cmd_change_user_pwd)

 

Python实现SSH远程登陆,并执行命令的方法

import paramiko 
 
def sshclient_execmd(hostname, port, username, password, execmd): 
paramiko.util.log_to_file(
"paramiko.log") s = paramiko.SSHClient() s.set_missing_host_key_policy(paramiko.AutoAddPolicy())
#连接 s.connect(hostname
=hostname, port=port, username=username, password=password)

#执行 stdin, stdout, stderr
= s.exec_command (execmd) stdin.write("Y") # Generally speaking, the first connection, need a simple interaction. print stdout.read() s.close() def main(): hostname = '10.***.***.**' port = 22 username = 'root' password = '******' execmd = "free"
#调用函数 sshclient_execmd(hostname, port, username, password, execmd)
if __name__ == "__main__": main()

 

Python 实现远程服务器(ssh)批量执行命令

 

 

import paramiko

#实例化ssh客户端 ssh = paramiko.SSHClient()
#创建默认的白名单 policy = paramiko.AutoAddPolicy()
#设置白名单 ssh.set_missing_host_key_policy(policy)
#链接服务器 ssh.connect( hostname = "192.168.2.186", #服务器的ip port = 22, #服务器的端口 username = "root", #服务器的用户名 password = "123" #用户名对应的密码 )
#远程执行命令 stdin,stdout,stderr = ssh.exec_command("ls") #exec_command 返回的对象都是类文件对象 #stdin 标准输入 用于向远程服务器提交参数,通常用write方法提交 #stdout 标准输出 服务器执行命令成功,返回的结果 通常用read方法查看 #stderr 标准错误 服务器执行命令错误返回的错误值 通常也用read方法 #查看结果,注意在Python3 字符串分为了:字符串和字节两种格式,文件返回的是字节

result = stdout.read().decode() print(result)

 

使用SSHClient封装Transport

我们可能会遇到  需要传输文件,有需要执行Linux命令的情况,  因为Transport对象只能传输文件,不能执行Linux命令,所以我们只需要创建一个SSHClient,然后通过SSHClient的 get_transport() 来创建Transport对象

 paramiko远程上传和下载

import paramiko
  
transport = paramiko.Transport(('192.168.1.1',22))
transport.connect(username='weiheng',password='weiheng123')
  
sftp = paramiko.SFTPClient.from_transport(transport)

# 将HelloWorld.py 上传至服务器 /tmp/1.py
sftp.put('/tmp/HelloWorld.py', '/tmp/1.py')

# 将1.py 下载到本地 HelloWorld
sftp.get('/tmp/1.py', '/tmp/HelloWorld')
  
transport.close()

 

'''给远程主机上传一个文件'''

from paramiko.ssh_exception import NoValidConnectionsError,AuthenticationException import paramiko def put(hostname,password,local_name,remote_name): try: transport = paramiko.Transport((hostname,22)) transport.connect(username='root',password=password) sftp = paramiko.SFTPClient.from_transport(transport) except AuthenticationException as e: return '主机%s密码错误' %(hostname) except Exception as e: return '未知错误: ',e else: sftp.put(local_name,remote_name) ##上传文件 try: # 如果远程主机有这个文件则返回一个对象,否则抛出异常 sftp.file(remote_name) print("上传成功.") except IOError: print("上传失败!") finally: transport.close() put('172.25.254.221','redhat','/home/kiosk/passwd','/mnt/test') ##远程主机ip,密码,本地文件,上传后的文件保存位置

 

'''从远程主机下载文件'''

from paramiko.ssh_exception import NoValidConnectionsError,AuthenticationException import paramiko import os def get(hostname,password,remote_name,local_name): try: transport = paramiko.Transport((hostname,22)) transport.connect(username='root',password=password) sftp = paramiko.SFTPClient.from_transport(transport) except AuthenticationException as e: return '主机%s密码错误' %(hostname) except Exception as e: return '未知错误: ',e else: #sftp.put(local_name,remote_name) ##上传文件 sftp.get(remote_name,local_name) ##下载文件 if os.path.exists(local_name): print('下载成功.') else: print('下载失败') finally: transport.close() get('172.25.254.221','redhat','/mnt/test','/home/kiosk/test111.txt')

 

sftp.close() 关闭sftp


sftp.file(filename, mode=‘r’, bufsize=-1) 读取文件


sftp.from_transport(s) 创建客户端通道


sftp.open(filename, mode=‘r’, bufsize=-1) 在远程服务器打开文件


sftp.put(localpath, remotepath, callback=None) localpath文件上传到远程服务器remotepath


sftp.get(remotepath, localpath, callback=None) 从远程服务器remotepath拉文件到本地localpath


sftp.remove(path) 删除文件

 

 

 

 

import paramiko
   
# 创建SSH对象
ssh = paramiko.SSHClient()
# 允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接服务器
ssh.connect(hostname='192.168.1.1', port=22, username='weiheng', password='weiheng123')
 
# 获取Transport对象 trans_obj = ssh_client.get_transport() sftp_obj = paramiko.SFTPClient.from_transport(trans_obj) sftp_obj.get_channel()

# 使用sftp_obj上传和下载文件 sftp_obj.put('source','target') sftp_obj.get('source','target') # 执行命令 stdin, stdout, stderr = ssh.exec_command('ls') # 获取命令结果 result = stdout.read()
# 关闭连接 ssh.close()

 

 

基于公钥密钥方式连接:

import paramiko
  
private_key = paramiko.RSAKey.from_private_key_file('/home/haoren/.ssh/id_rsa')
  
# 创建SSH对象
ssh = paramiko.SSHClient()
# 允许连接不在know_hosts文件中的主机
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接服务器
ssh.connect(hostname='192.168.1.10', port=22, username='zt', key=private_key)
  
# 执行命令
stdin, stdout, stderr = ssh.exec_command('ls -l')
# 获取命令结果
result = stdout.read()
  
# 关闭连接
ssh.close()

 

 

批量连接主机

from paramiko.ssh_exception import NoValidConnectionsError,AuthenticationException

def connect(cmd,hostname,user,password):
    import paramiko

    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    try:
        client.connect(
            hostname=hostname,
            username=user,
            password=password
        )
        stdin, stdout, stderr = client.exec_command(cmd)
        a = stdout.read().decode('utf-8')
        print(stdout.read().decode('utf-8'))
        return a
    except NoValidConnectionsError as e:
        return '主机%s连接失败' %(hostname)
    except AuthenticationException as e:
        return '主机%s密码错误' %(hostname)
    except Exception as e:
        return '未知错误:',e
    finally:
        client.close()

with open('/home/kiosk/passwd') as f:            ##文件格式按照下面的要求书写(ip:用户名:密码)
    for line in f:
        hostname,username,password = line.strip().split(':')
        res = connect('hostname',hostname,username,password)               #调用函数
        # print(hostname.center(50,'*'))
        print('主机名:', res)

 

 

 

 

 

 

 

 

 

 

 

paramiko+threading 实现远程服务器批量执行命令

 

 

 

 #coding:utf-8
 
 import sys
 import paramiko
 import threading
 
 def getConnection(ip,username,password,command,port = 22):
#实例化对象 ssh = paramiko.SSHClient() policy = paramiko.AutoAddPolicy() ssh.set_missing_host_key_policy(policy)

#连接 ssh.connect( hostname
= ip, # 服务器的ip port = port, # 服务器的端口 username = username, # 服务器的用户名 password = password # 用户名对应的密码 )

#执行 stdin, stdout, stderr
= ssh.exec_command(command) result = stdout.read().decode() error = stderr.read().decode() print("+++++++++++++++++++++++start++++++++++++++++++++") print("[connect success] | ip : %s" % ip) print("result: \n %s"%result) if error != " ": print("error: \n %s"%error) print("+++++++++++++++++++++++done++++++++++++++++++++") ssh.close()


#我们采用多线程 def main(host_list,command): thread_list = []
for ip,username,password in host_list:
thread
= threading.Thread(target = getConnection, args = (ip,username,password,command)) thread_list.append(thread)
for t in thread_list: t.start() for t in thread_list: t.join() if __name__ == "__main__": host_list = [ ("192.168.2.186", "root", "123"), ("192.168.2.88", "root", "123"), ] command = sys.argv[1] main(host_list,command)

 

 

 

 

    

 

 

#单线程运行

from time import sleep
 
def loop(num,sleeptime):
    """
    当前函数作为功能函数
    :param num: 函数的编号
    :param sleeptime:  睡眠的时间
    """
    print("loop %s is start"%num)
    sleep(sleeptime)
    print("loop %s is done"%num)
 
def main():
    sleep_list = [3,2] #睡眠时间
    lenth = len(sleep_list) #获取列表长度
    print("all is start") 
    for i in range(lenth):
        loop(i,sleep_list[i]) #按照列表长度和列表内容调用函数
    print("all is down")
 
 
if __name__ == "__main__":
    main()



#多线程运行

 import threading
 from time import sleep
 
 def loop(num,sleeptime):
     """
     当前函数作为功能函数
     :param num: 函数的编号
     :param sleeptime:  睡眠的时间
     """
     print("loop %s is start"%num)
     sleep(sleeptime)
     print("loop %s is done"%num)
 
 def main():
     sleep_list = [3,2] #睡眠时间
     lenth = len(sleep_list) #获取列表长度
thread_list = [] print("all is start") for i in range(lenth):
#threading.Thread 就是用线程来执行我们的功能 t = threading.Thread(target = loop,args = (i,sleep_list[i])) #按照列表长度和列表内容调用函数 thread_list.append(t) #将生成的线程添加到列表里
for t in thread_list: t.start() #开始执行线程 for t in thread_list: t.join() #挂起线程,到所有线程结束 print("all is down")    

推荐阅读