狂自私

导航

paramiko的常规使用示例-python

  本示例全程使用函数式编程思想,面对对象的编程思想从未体现。

  若有不足之处,还望斧正,谢谢各位前辈、大佬、同行者。

import paramiko
import re
import time
import os
'''
本端均指Windows
远端均指常规Linux发行版
写入文件的错误记录:
将会使用errInfoFileList和outInfoFileList字典中指定为文件名称写入,每次运行时,每个主机的错误信息均会记录到errInfoFileList[host]指定的文件中。
'''

#passwords = {'2409:8069:5A06:1405::127:2021':'Cmcc_2o20','2409:8069:5A06:1405::127:2022':'Cmcc_2o20','2409:8069:5A06:1405::127:2031':'Admin_123','2409:8069:5A06:1405::127:2032':'Admin_123'}
#hosts = ['2409:8069:5A06:1405::127:2021','2409:8069:5A06:1405::127:2022','2409:8069:5A06:1405::127:2031','2409:8069:5A06:1405::127:2032']
#users = {'2409:8069:5A06:1405::127:2021':'admin','2409:8069:5A06:1405::127:2022':'admin','2409:8069:5A06:1405::127:2031':'admin','2409:8069:5A06:1405::127:2032':'admin'}
#passwords = {'s3.nsloop.com':'Lovedan'}
#hosts = ['s3.nsloop.com']
#users = {'s3.nsloop.com':"admin"}
#hosts=['2409:8080:5a0a:750c::8241']
#passwords = {'2409:8080:5a0a:750c::8241':'Lovedan'}
#users = {'2409:8080:5a0a:750c::8241':"admin"}
hosts=['192.168.50.25']
passwords = {'192.168.50.25':'Lovedan'}
users = {'192.168.50.25':"Administrator"}

errInfoFileList={}      #用于在同一次运行中保持文件名相同
outInfoFileList={}      #用于在同一次运行中保持文件名相同

def my_exec_command(SSHClient__,commandString,getPty=False):
    '''
    进行了一次错误捕捉,仍然返回三个经典参数
    get_pty:是否保持终端
    '''
    try:
        stdin, stdout, stderr = SSHClient__.exec_command(commandString,get_pty = getPty)
    except Exception as errMsg:
        print("虽然exec_command报错了,但是不需要管他.")
        print("这是报错信息:")
        print("{}:\t{}".format(Exception,errMsg))
    return stdin, stdout, stderr

def isError(stdErr):
    '''
    检查命令的输出有没有错误信息,有返回True,和错误信息(string 类型),没有返回False和None
    请传入stderr,而不是stdin或者stdout
    '''
    errStr = stdErr.read().decode()
    if len(errStr) == 0:
        return False,None
    else:
        return True,errStr

def errInfoToFile(host,errinfo,commandString):
    '''
    用于将命令执行过程中的错误信息保存下来
    '''
    if host not in errInfoFileList:
        currentTime = time.localtime()
        fileTime=str(currentTime.tm_year) + "" + str(currentTime.tm_mon) + "" + str(currentTime.tm_mday) + "" + str(currentTime.tm_hour) + "" + str(currentTime.tm_min) + ""
        fileName = re.sub(r':|\.','-',host) + '_commandErrorLog_{}.txt'.format(fileTime)
        errInfoFileList[host] = fileName
        with open(fileName,'a',encoding= 'UTF8',newline='') as errFile:
            print("命令:{} 的错误信息".format(commandString),file=errFile)
            print(errinfo,file=errFile,end='')
            print('',file=errFile)
    else:
        fileName = errInfoFileList[host]
        errInfoFileList[host] = fileName
        with open(fileName,'a',encoding= 'UTF8',newline='') as errFile:
            print("命令:{} 的错误信息:".format(commandString),file=errFile)
            print(errinfo,file=errFile,end='')
            print('',file=errFile)

def outInfoToFile(host,outinfo,commandString):
    '''
    用于将命令执行过程中的输出信息保存下来
    '''
    if host not in outInfoFileList:
        currentTime = time.localtime()
        fileTime=str(currentTime.tm_year) + "" + str(currentTime.tm_mon) + "" + str(currentTime.tm_mday) + "" + str(currentTime.tm_hour) + "" + str(currentTime.tm_min) + ""
        fileName = re.sub(r':|\.','-',host) + '_commandOutLog_{}.txt'.format(fileTime)
        outInfoFileList[host] = fileName
        with open(fileName,'a',encoding= 'UTF8',newline='') as outFile:
            print("命令:{} 的输出信息:".format(commandString),file=outFile)
            print(outinfo,file=outFile,end='')
            print('',file=outFile)
    else:
        fileName = outInfoFileList[host]
        outInfoFileList[host] = fileName
        with open(fileName,'a',encoding= 'UTF8',newline='') as outFile:
            print("命令:{} 的输出信息:".format(commandString),file=outFile)
            print(outinfo,file=outFile,end='')
            print('',file=outFile)

def checkAndEstablishRemotePath(sftpclient,host,path=None):
    #检查远程主机上目标目录是否存在,存在返回True
    #不存在则建立,建立失败返回None,并输出错误原因到文件中,建立成功返回True
    #此函数只适用于Linux,测试的发行版为CentOS 6-7
    #且需要创建的路径为绝对路径而不是相对路径
    if path == None:
        errInfoToFile(sftpclient.host,"path:{} 不存在。".format(path),'cd None')
        return None
    try:
        sftpclient.listdir(path)
    except Exception as errMsg:
        #print('{}:{}'.format(Exception,errMsg))
        try:
            sftpclient.mkdir(path)
        except Exception as errMsg:
            errInfoToFile(host,'{}:{}'.format(Exception,errMsg),'sftpclient.mkdir({})'.format(path))
            print('{}:{}'.format(Exception,errMsg))
            return None
        return True
    else:
        return True

def checkAndEstablishLocalPath_win(path=None):
    #检查path指定的路径本地是否存在,若不存在,创建它
    #若存在,返回True
    #若创建成功,返回True,若创建失败,打印原因,然后返回None
    #此函数仅适用于Windows主机
    if path == None:
        return None
    if os.path.exists(path):
        return True
    else:
        #创建
        try:
            os.mkdir(path)
        except Exception as errMsg:
            errInfoToFile('localhost','{}:{}'.format(Exception,errMsg),'os.mkdir({})'.format(path))
            print('{}:{}'.format(Exception,errMsg))
            return None
        return True

def CheckRemoteHostFilePathExists(sftpclient,filePath=None):
    '''
    检查远程主机上是否存在需要下载的文件,存在返回True,不存在返回None
    '''
    if filePath == None:
        errInfoToFile(sftpclient.host,"path:{} 不存在。".format(filePath),'cd None')
        return None
    else:
        try:
            sftpclient.stat(filePath)
        except Exception as errMsg:
            errInfoToFile('localhost','{}:{}'.format(Exception,errMsg),'sftpclient.stat({})'.format(filePath))
            print('{}:{}'.format(Exception,errMsg))
            return None
        return True

def main_():
    #普通命令
    commandList = ['pwd','whoami']
    ssh = paramiko.SSHClient()
    for host in hosts:
        #若主机之前未连接过,自动选择yes添加到本地know_hosts文件
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        ssh.connect(host,username=users[host],password=passwords[host],timeout=10)
        for command in commandList:
            stdin, stdout, stderr = my_exec_command(ssh,command)
            chcekErrRet =  isError(stderr)
            if chcekErrRet[0]:
                errInfoToFile(host,chcekErrRet[1],command)
                print(chcekErrRet[1])
                #是否要停止继续执行命令
            outInfo = stdout.read().decode()
            outInfoToFile(host,outInfo,command)
            print(outInfo)
    ssh.close()
def main_sudo():
    #sudo 命令
    commandList = ['ls -al /home/administrator','cat /etc/shadow']
    ssh = paramiko.SSHClient()
    for host in hosts:
        #若主机之前未连接过,自动选择yes添加到本地know_hosts文件
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        try:
            ssh.connect(host,port='32215',username=users[host],password=passwords[host],timeout=10)
        except Exception as errMsg:
            print("({}:{}".format(Exception,errMsg))
            errInfoToFile(host,"({}:{}".format(Exception,errMsg),"ssh@{}".format(host)) #最好加上端口信息
            continue
        for command in commandList:
            #构建sudo命令:
            command = 'echo {} | '.format(passwords[host]) + command
            print(command)
            stdin, stdout, stderr = my_exec_command(ssh,command,True)
            chcekErrRet =  isError(stderr)
            if chcekErrRet[0]:
                errInfoToFile(host,chcekErrRet[1],command)
                print(chcekErrRet[1])
                continue
            outInfo = stdout.read().decode()
            if len(re.findall(r'\[sudo\]\s{}'.format(users[host]),outInfo,re.IGNORECASE)) != 0:
                #输入密码
                time.sleep(3) # 与终端交互,输入密码 注意:要是与终端交互最好sleep一下,否则会出现卡住的现象
                stdin.write(passwords[host]+'\n')
                stdin.flush()
            outInfo += stdout.read().decode()
            outInfoToFile(host,outInfo,command)
            print(outInfo)
    ssh.close()
def main_get_put():
    '''
    上传单个文件
    下载单个文件
    '''
    putFileFullPathList = [r'F:\temp\old-2020年11月6日\odbsci.xml']
    putFileToRemotePathList = [r'/home/admin/']
    getFileLocalPathList = [r'F:\temp\old-2020年11月6日']
    getFileRemotePathList = [r'/home/admin/df.txt']
    port = 22
    for host in hosts:
        transport = paramiko.Transport((host,port))
        try:
            transport.connect(username=users[host],password=passwords[host])
            sftpClient = paramiko.SFTPClient.from_transport(transport)
        except Exception as errMsg:
            print('{}:{}'.format(Exception,errMsg))
            errInfoToFile(host,'{}:{}'.format(Exception,errMsg),'sftp连接{}'.format(host))
            continue
        #上传文件
        #若有重名文件,执行覆盖操作,请上传之前注意这一点。
        #也可以写一个检查远程主机的目标目录中是否存在这个文件。然后做提示
        for putFile in putFileFullPathList:
            if os.path.exists(putFile):         #检查本地文件是否存在
                for putFileToRemotePath in putFileToRemotePathList:
                    if checkAndEstablishRemotePath(sftpClient,host,putFileToRemotePath):
                        #远程目录必须指定文件名,这里使用的是本地文件名称,若是需要重命名,可以通过传参等方式重构本处。
                        fileName = re.findall(r'(?<=\\)[^\\]+$',putFile,re.IGNORECASE)
                        if len(fileName) != 0:
                            fileName = fileName[0]
                            try:
                                sftpClient.put(putFile,putFileToRemotePath + fileName)
                            except Exception as errMsg:
                                print('{}:{}'.format(Exception,errMsg))
                                errInfoToFile(host,'{}:{}'.format(Exception,errMsg),'sftp上传文件:{} 到远程目录:{}'.format(putFile,putFileToRemotePath))
                            else:
                                print('成功上传 {} 到 {}'.format(fileName,putFileToRemotePath))
                        else:
                            print("未匹配到文件名,不可上传。")
                            errInfoToFile(host,"未匹配到文件名,不可上传。",'sftp上传文件:{} 到远程目录:{}'.format(putFile,putFileToRemotePath))
        
        #下载文件
        #也是默认执行
        #这里不进行提示文件已存在,是否覆盖。
        for lcoalPath in getFileLocalPathList:
            if checkAndEstablishLocalPath_win(lcoalPath):
                for remoteFilePath in getFileRemotePathList:
                    if CheckRemoteHostFilePathExists(sftpClient,remoteFilePath):
                        fileName = re.findall(r'(?<=/)[^/]+$',remoteFilePath,re.I)
                        if len(fileName) != 0:
                            fileName = fileName[0]
                        else:
                            print("远程文件路径:{} 未能匹配到文件名。".format(remoteFilePath))
                            errInfoToFile(host,"远程文件路径:{} 未能匹配到文件名。".format(remoteFilePath),r"re.findall(r'(?<=/)[^/]+$',{},re.I)".format(remoteFilePath))
                            continue
                        try:
                 #这里不允许使用相对路径 sftpClient.get(remoteFilePath,
"{}\\{}".format(lcoalPath,fileName)) except Exception as errMsg: print('{}:{}'.format(Exception,errMsg)) errInfoToFile(host,'{}:{}'.format(Exception,errMsg),'sftp下载文件 {} 到本地目录 {} '.format(remoteFilePath,lcoalPath)) continue sftpClient.close() def RemotePathStructure(LocalPath,RemotePath): #通过本地目录,来构造远程主机上的文件路径 #本地主机指Windows #远程主机指Linux(常规发行版) #返回构造完成的远程文件目录列表以及本地路径列表,返回值中,第一个值是远端文件列表,第二个是本地路径列表 #LocalPath是string类型,且不以斜杠结尾 #RemotePath是string类型,且不以反斜杠结尾 if len(LocalPath) == 0 or len(RemotePath) == 0: print('本地路径或者远程路径的长度不能为0') errInfoToFile('localhost',"本地路径或者远程路径的长度不能为0","len(LocalPath) == 0 or len(RemotePath) == 0") return [] if LocalPath[-1] == '\\': LocalPath = LocalPath[0:len(LocalPath)-1] if RemotePath[-1] == '/': RemotePath = RemotePath[0:len(LocalPath)-1] RemotePathList =[] lcoalpathList = [] if os.path.exists(LocalPath): FilePethList = os.listdir(LocalPath) for fileName in FilePethList: filePath = "{}\\{}".format(LocalPath,fileName) if os.path.isdir(filePath): #若不需要追踪链接,应该先使用os.path.islink来判断 RmPath = "{}/{}".format(RemotePath,fileName) RPL,LPL = RemotePathStructure(filePath,RmPath) RemotePathList.extend(RPL) lcoalpathList.extend(LPL) continue else: RmPath = "{}/{}".format(RemotePath,fileName) RemotePathList.append(RmPath) lcoalpathList.append(filePath) else: print('本地路径不存在') errInfoToFile('localhost',"本地路径不存在","os.path.exists(p{})".format(LocalPath)) return [] return RemotePathList,lcoalpathList def lcoalPathStructure(host,port,username,password,remotePath,localpath): #使用ssh方式从远程主机上获取目录,文件信息,然后构造需要下载的远程文件的绝对路径和本地存放的绝对路径 #参数均为string类型。 #LocalPath是string类型,且不以斜杠结尾 #RemotePath是string类型,且不以反斜杠结尾 #返回构造完成的远程文件路径列表和本地文件路径列表 #有许多情况都会导致返回空列表,比如传参类型不对,长度为0,连接远程失败,登录的用户无法执行命令 #返回值中,第一个是本地路径列表,第二个是远端路径列表 #所涉及到的命令:ls -l 、cd ''' if not (repr(type(remotePath)) != repr(type('')) or repr(type(localpath)) != repr(type(''))): print('参数:remotePath或者localpath的类型不为string。type(remotePath):{}\ttype(localpath):{}'.format(type(remotePath),type(localpath))) errInfoToFile(host,'参数:remotePath或者localpath的类型不为string。type(remotePath):{}\ttype(localpath):{}'.format(type(remotePath),type(localpath)),"if not (repr(type(remotePath)) != repr(type('')) or repr(type(localpath)) != repr(type(''))):") return [],[] ''' if not(len(remotePath) != 0 or len(localpath) != 0): print('参数:remotePath或者localpath的长度为0。len(remotePath):{}\tlen(localpath):{}'.format(len(remotePath),len(localpath))) errInfoToFile(host,'参数:remotePath或者localpath的长度为0。len(remotePath):{}\tlen(localpath):{}'.format(len(remotePath),len(localpath)),"if not(len(remotePath) != 0 or len(localpath) != 0):") return [],[] ssh = paramiko.SSHClient() #若主机之前未连接过,自动选择yes添加到本地know_hosts文件 ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: ssh.connect(host,username=users[host],password=passwords[host],timeout=10) except Exception as errMsg: print('{}:{}'.format(Exception,errMsg)) errInfoToFile(host,'{}:{}'.format(Exception,errMsg),'ssh连接{}'.format(host)) return [],[] command = 'ls -l {}'.format(remotePath) try: stdin, stdout, stderr = my_exec_command(ssh,command) except Exception as errMsg: print('{}:{}'.format(Exception,errMsg)) errInfoToFile(host,'{}:{}'.format(Exception,errMsg),command) return [],[] chcekErrRet = isError(stderr) if chcekErrRet[0]: errInfoToFile(host,chcekErrRet[1],command) print(chcekErrRet[1]) ls_l_command_out = stdout.read().decode() outLineList = re.findall(r'.+',ls_l_command_out,re.I) #print(outLineList) retRemotePathList=[] retlocalPathList=[] outLineList = outLineList[1:len(outLineList)] #忽略第一行数据 if len(outLineList) != 0: for outLine in outLineList: mode = re.findall(r'^[a-z-]{10}',outLine,re.I) if len(mode) != 0: mode= mode[0] #print("mode[0]:{}".format(mode[0])) if mode[0] == 'd' or mode[0] == 'D': #目录 fileName ='' fileName_1 = re.findall(r'(?<=\d\s\d\d:\d\d ).+',outLine,re.I) fileName_2 = re.findall(r'(?<=\d\s\d\d\d\d ).+',outLine,re.I) if len(fileName_1) != 0 and len(fileName_2) != 0: input("快来看,真的有同时符合两种模式的文件哎:\n{}".format(outLine)) if len(fileName_1) == 0 and len(fileName_2) == 0: input("没有匹配到目录名,检查一下,outLine:\n{}\nfileName_1:{}\tfileName_2:{}".format(outLine,fileName_1,fileName_2)) if len(fileName_1) != 0: fileName = fileName_1[0] if len(fileName_2) != 0: fileName = fileName_2[0] #递归 remotePath_ = "{}/{}".format(remotePath,fileName) localpath_ = "{}\\{}".format(localpath,fileName) LPL,RPL = lcoalPathStructure(host,port,username,password,remotePath_,localpath_) #列表类型 retlocalPathList.extend(LPL) retRemotePathList.extend(RPL) elif mode[0] == 'l' or mode[0] == 'L': #链接 fileName ='' fileName_1 = re.findall(r'(?<=\d\s\d\d:\d\d ).+?(?= ->)',outLine,re.I) fileName_2 = re.findall(r'(?<=\d\s\d\d\d\d ).+?(?= ->)',outLine,re.I) if len(fileName_1) != 0 and len(fileName_2) != 0: input("快来看,真的有同时符合两种模式的文件哎:\n{}".format(outLine)) if len(fileName_1) == 0 and len(fileName_2) == 0: input("没有匹配到链接名,检查一下,outLine:\n{}\nfileName_1:{}\tfileName_2:{}".format(outLine,fileName_1,fileName_2)) if len(fileName_1) != 0: fileName = fileName_1[0] if len(fileName_2) != 0: fileName = fileName_2[0] linkPath = re.findall(r'(?<= ->\s).+',outLine,re.I) if(linkPath) != 0: linkPath = linkPath[0] else: input("没有匹配到链接所指向的内容,检查一下:\n{}".format(outLine)) #检查是否是目录 command = "cd {}/{}".format(remotePath,fileName) try: stdin, stdout, stderr = my_exec_command(ssh,command) except Exception as errMsg: print('{}:{}'.format(Exception,errMsg)) errInfoToFile(host,'{}:{}'.format(Exception,errMsg),command) continue chcekErrRet = isError(stderr) if chcekErrRet[0]: #说明不是目录 if linkPath[0] != '/': RPL = "{}/{}".format(remotePath,linkPath) else: RPL = linkPath LPL = "{}\\{}".format(localpath,fileName) #字符串类型 retlocalPathList.append(LPL) retRemotePathList.append(RPL) else: #是目录,递归 if linkPath[0] != '/': remotePath_ = "{}/{}".format(remotePath,linkPath) else: remotePath_ = linkPath localpath_ = "{}\\{}".format(localpath,fileName) LPL,RPL = lcoalPathStructure(host,port,username,password,remotePath_,localpath_) #列表类型 retlocalPathList.extend(LPL) retRemotePathList.extend(RPL) else: #其他文件 fileName ='' fileName_1 = re.findall(r'(?<=\d\s\d\d:\d\d ).+',outLine,re.I) fileName_2 = re.findall(r'(?<=\d\s\d\d\d\d ).+',outLine,re.I) if len(fileName_1) != 0 and len(fileName_2) != 0: input("快来看,真的有同时符合两种模式的文件哎:\n{}".format(outLine)) if len(fileName_1) == 0 and len(fileName_2) == 0: input("没有匹配到文件名,检查一下,outLine:\n{}\nfileName_1:{}\tfileName_2:{}".format(outLine,fileName_1,fileName_2)) if len(fileName_1) != 0: fileName = fileName_1[0] if len(fileName_2) != 0: fileName = fileName_2[0] RPL = "{}/{}".format(remotePath,fileName) LPL = "{}\\{}".format(localpath,fileName) #字符串类型 retlocalPathList.append(LPL) retRemotePathList.append(RPL) else: input("请确认,匹配文件属性值未匹配到:{}".format(outLine)) else: #对于空目录 retRemotePathList.append(remotePath) filename = re.findall(r'(?<=/)[^/]+$',remotePath,re.I) if len(filename) == 0: return [],[] else: filename = filename[0] retlocalpath = "{}\\{}".format(localpath,filename) retlocalPathList.append(retlocalpath) #print("retlocalPathList:{}\nretRemotePathList:{}".format(retlocalPathList,retRemotePathList)) return retlocalPathList,retRemotePathList def main(): #上传整个目录 #下载整个目录 #若目录中含有目录链接,会追踪该链接。 ''' putLocalPathList = [r'D:\Music'] #上传的本地目录 putRemotePathList = ['/home/admin/Music'] #上传到远程主机的路径 localFilePathList = [] #存储本地待上传或下载的文件路径 remoteFilePathList = [] #存储远程待上传或下载的文件路径 port = 22 #上传 for localpath in putLocalPathList: for remotePath in putRemotePathList: remoteFilePathList,localFilePathList = RemotePathStructure(localpath,remotePath) if len(remoteFilePathList) == len(localFilePathList): for host in hosts: transport = paramiko.Transport((host,port)) try: transport.connect(username=users[host],password=passwords[host]) sftpClient = paramiko.SFTPClient.from_transport(transport) except Exception as errMsg: print('{}:{}'.format(Exception,errMsg)) errInfoToFile(host,'{}:{}'.format(Exception,errMsg),'sftp连接{}'.format(host)) continue for index in range(len(remoteFilePathList)): #print(remoteFilePathList[index]) remotePath = re.findall(r".*/",remoteFilePathList[index],re.I) if len(remotePath) == 0: print("未从远程文件路径列表中的元素中匹配到远程路径:{}".format(remoteFilePathList[index])) errInfoToFile(host,"未从远程文件路径列表中的元素中匹配到远程路径","re.findall(r'.*/',{},re.I)".format(remoteFilePathList[index])) continue else: remotePath = remotePath[0] if checkAndEstablishRemotePath(sftpClient,host,remotePath): #远程目录必须指定文件名,这里使用的是本地文件名称,若是需要重命名,可以通过传参等方式重构本处。 try: sftpClient.put(localFilePathList[index],remoteFilePathList[index]) except Exception as errMsg: print('{}:{}'.format(Exception,errMsg)) errInfoToFile(host,'{}:{}'.format(Exception,errMsg),'sftp上传文件:{} 到远程目录:{}'.format(localFilePathList[index],remoteFilePathList[index])) else: print('成功上传 {} 到 {}'.format(localFilePathList[index],remoteFilePathList[index])) else: print("远程目录未创建成功") else: print("构造出来的本地文件列表和远程文件列表数量不一致") ''' getLocalPathList = [r'C:\Users\Administrator\Desktop\temp\2020年11月11日\test'] #上传的本地目录 getRemotePathList = ['/etc'] #上传到远程主机的路径 localFilePathList = [] #存储本地待上传或下载的文件路径 remoteFilePathList = [] #存储远程待上传或下载的文件路径 port = 22 #也许可以设置一个全局端口字典 #下载 for localpath in getLocalPathList: for remotePath in getRemotePathList: for host in hosts: localFilePathList,remoteFilePathList = lcoalPathStructure(host,port,users[host],passwords[host],remotePath,localpath) if (len(remoteFilePathList) == len(localFilePathList)) and (remoteFilePathList != [] and localFilePathList != []): print("记录并构造了{}个文件路径。".format(len(localFilePathList))) transport = paramiko.Transport((host,port)) try: transport.connect(username=users[host],password=passwords[host]) sftpClient = paramiko.SFTPClient.from_transport(transport) except Exception as errMsg: print('{}:{}'.format(Exception,errMsg)) errInfoToFile(host,'{}:{}'.format(Exception,errMsg),'sftp连接{}'.format(host)) continue successfulNumber = 0 #记录下载成功的数量 failedNumber = 0 #记录下载失败的数量,失败的记录会输出到脚本同目录下的日志文件中 for index in range(len(remoteFilePathList)): localPath = re.findall(r".+\\",localFilePathList[index],re.I) if len(localPath) == 0: print("未从本地文件路径列表中的元素中匹配到本地路径:{}".format(localFilePathList[index])) errInfoToFile(host,"未从远程文件路径列表中的元素中匹配到本地路径","re.findall(r'.+\\',{},re.I)".format(localFilePathList[index])) continue else: localPath = localPath[0] if not os.path.exists(localPath): try: #创建本地目录 os.makedirs(localPath) except Exception as errMsg: print('{}:{}'.format(Exception,errMsg)) errInfoToFile(host,'{}:{}'.format(Exception,errMsg),"创建本地目录:{}".format(localPath)) failedNumber += 1 continue #若需要重命名,请增加逻辑 try: sftpClient.get(remoteFilePathList[index],localFilePathList[index]) except Exception as errMsg: print('{}:{}'.format(Exception,errMsg)) errInfoToFile(host,'{}:{}'.format(Exception,errMsg),'sftp下载文件:{} 到本地目录:{}'.format(remoteFilePathList[index],localFilePathList[index])) failedNumber += 1 else: print('成功下载文件 {} 到 {}'.format(remoteFilePathList[index],localFilePathList[index])) successfulNumber += 1 #print(localFilePathList[index]) print("记录的文件里边数目:{}\n下载成功的文件的数量:{}\n下载失败的文件数量:{}".format(len(localFilePathList),successfulNumber,failedNumber)) else: print("构造出来的本地文件列表和远程文件列表数量不一致;或者均为空列表。") main()

后续可能会更新多线程或者多进程的版本。

#这里不允许使用相对路径

posted on 2020-11-15 16:10  狂自私  阅读(308)  评论(0编辑  收藏  举报