zoukankan      html  css  js  c++  java
  • 用python实现远程复制 (scp + expect )

    scp 功能很强大,但需要人工输入 password, 当然可以通过把 公钥保存在远程主机的 ~/.ssh 目录中,而后就不用输入password,但这需要配置.

    用 sshpass 可能在命令输入 password, 但 需要用 “sudo apt-get install sshpass” 安装

    如果不想用上面两种方法,可以用 expect 编写脚本可以帮助我们自动交互

    虽然 python 也提供 pexpect  模块,但既然 expect 很简单,为何不直接用 os.system() 去执行呢?

    下面是我编写的类,实现了远程复制 

    [html] view plaincopy
     
    1. class RemoteShell:  
    2.   
    3.     def __init__(self, host, user, pwd):  
    4.         self.host = host  
    5.         self.user  = user  
    6.         self.pwd  = pwd  
    7.   
    8.   
    9.     def put(self, local_path, remote_path):  
    10. scp_put = '''  
    11. spawn scp %s %s@%s:%s  
    12. expect "(yes/no)?" {  
    13. send "yes "  
    14. expect "password:"  
    15. send "%s "  
    16. } "password:" {send "%s "}  
    17. expect eof  
    18. exit'''  
    19.         os.system("echo '%s' > scp_put.cmd" % (scp_put % (os.path.expanduser(local_path), self.user, self.host, remote_path, self.pwd, self.pwd)))  
    20.         os.system('expect scp_put.cmd')  
    21.         os.system('rm scp_put.cmd')  


    但发现每次文件都没有复制完,我想看expect 究竟做了什么事情,还好 expect 提供 -d 参数给出更多的信息。

    最后发现是被复制文件太大,expect 超时退出了

    在脚本前加入 “set timeout -1" 就OK了

    [html] view plaincopy
     
    1. scp_put = '''  
    2. set timeout -1  
    3. spawn scp %s %s@%s:%s  
    4. expect "(yes/no)?" {  
    5. send "yes "  
    6. expect "password:"  
    7. send "%s "  
    8. } "password:" {send "%s "}  
    9. expect eof  
    10. exit'''  


    总结

    1) expect 每一条语句都是顺序执行

    [html] view plaincopy
     
    1.   

     因为scp 可能先返回 (yes/no)? 再 返回 password:, 也可能直接返回password:, 考虑顺序关系,上面语句的层次关系其实如下:

    [html] view plaincopy
     
    1. expect "(yes/no)?" {   send "yes "  
    2.                        expect "password:"  
    3.                        send "%s "  
    4.                     }   
    5.        "password:" {send "%s "}  


    2) 每当 spawn 的程序有输出的时候的,expect都会去匹配, 如果匹配不上,就等下次有输出,再次执行当前的 expect, 直到超时 (我用 expect -d 去追踪,得到的结论);当然可以设置没有超时 "set timeout -1"

    3) 如果  expect 退出, 被它 spawn 的程序会被 kill 掉

    4) spawn 结束的时候,它向标准输出的的 eof 会被 expect 检测到,正好作为 expect 脚本退出的时机。

    对于 scp 可以先检测 100%,因为 scp 会输出复制进度,再检测 eof

    [html] view plaincopy
     
    1. expect "100%%"  
    2. expect eof  

    5) expect 是部分匹配,所以不要担心自己不知道程序的完整输出

  • 相关阅读:
    [PHP]socket的连接超时 与 读取/写入超时
    [PHP]引用返回与节省内存
    [PHP]实体类基类和序列化__sleep问题
    [PHP]日志处理error_log()函数和配置使用
    [PHP] 使用反射实现的控制反转
    [PHP] debug_backtrace()可以获取到代码的调用路径追踪
    [TCP/IP] TCP的传输连接管理
    [PHP] sys_get_temp_dir()和tempnam()函数报错与环境变量的配置问题
    [PHP] ubuntu下使用uuid扩展获取uuid
    [Linux] host dig nslookup查询域名的DNS解析
  • 原文地址:https://www.cnblogs.com/hushaojun/p/4903287.html
Copyright © 2011-2022 走看看