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()
后续可能会更新多线程或者多进程的版本。
#这里不允许使用相对路径