【问题标题】:Python Paramiko directory walk over SFTPPython Paramiko 目录遍历 SFTP
【发布时间】:2019-11-02 09:59:42
【问题描述】:

如何通过 SSH 在另一台计算机上执行os.walk()?问题是 os.walk() 在本地机器上执行,我想 ssh 到另一台主机,遍历目录并为其中的每个文件生成 MD5 哈希。

到目前为止我写的看起来像这样(下面的代码),但它不起作用。任何帮助将不胜感激。

try:
    hash_array = []
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect('sunbeam', port=22, username='xxxx', password='filmlight')

    spinner.start()
    for root, dirs, files in os.walk(_path):
        for file in files:
            file_path = os.path.join(os.path.abspath(root), file)
            
            #  generate hash code for file
            hash_array.append(genMD5hash(file_path))
            
            file_nb += 1
    spinner.stop()
    spinner.ok('Finished.')

    return hash_array
except Exception as e:
    print(e)
    return None
finally:
    ssh.close() 

【问题讨论】:

    标签: python ssh sftp paramiko


    【解决方案1】:

    要使用 Paramiko 递归列出目录,使用标准文件访问接口 SFTP,您需要使用 SFTPClient.listdir_attr 实现递归函数:

    from stat import S_ISDIR, S_ISREG
    
    def listdir_r(sftp, remotedir):
        for entry in sftp.listdir_attr(remotedir):
            remotepath = remotedir + "/" + entry.filename
            mode = entry.st_mode
            if S_ISDIR(mode):
                listdir_r(sftp, remotepath)
            elif S_ISREG(mode):
                print(remotepath)
    

    基于Python pysftp get_r from Linux works fine on Linux but not on Windows


    或者,pysftp 实现 os.walk 等效项:Connection.walktree


    虽然使用 SFTP 协议获取远程文件的 MD5 时会遇到麻烦。

    虽然 Paramiko 的 SFTPFile.check 支持它,但大多数 SFTP 服务器(尤其是最广泛使用的 SFTP/SSH 服务器 - OpenSSH)不支持。 请参阅:
    How to check if Paramiko successfully uploaded a file to an SFTP server?
    How to perform checksums during a SFTP file transfer for data integrity?

    所以你很可能不得不求助于使用 shell md5sum 命令(如果你甚至有 shell 访问权限)。如果无论如何都必须使用 shell,请考虑使用 shell 列出文件,因为这将比通过 SFTP 快很多。

    md5 all files in a directory tree

    使用SSHClient.exec_command:
    Comparing MD5 of downloaded files against files on an SFTP server in Python


    强制性警告:不要使用AutoAddPolicy - 这样做会失去对MITM attacks 的保护。如需正确解决方案,请参阅Paramiko "Unknown Server"

    【讨论】:

      【解决方案2】:

      基于previous answer,这里的版本不需要递归,而是使用print 命令返回路径列表。

      from stat import S_ISDIR, S_ISREG
      from collections import deque
      
      def listdir_r(sftp, remotedir):
          dirs_to_explore = deque([remotedir])
          list_of_files = deque([])
      
          while len(dirs_to_explore) > 0:
              current_dir = dirs_to_explore.popleft()
      
              for entry in sftp.listdir_attr(current_dir):
                  current_fileordir = current_dir + "/" + entry.filename
      
                  if S_ISDIR(entry.st_mode):
                      dirs_to_explore.append(current_fileordir)
                  elif S_ISREG(entry.st_mode):
                      list_of_files.append(current_fileordir)
      
          return list(list_of_files)
      

      【讨论】: