zoukankan      html  css  js  c++  java
  • python--pexpect

      大家好,最近工作比较忙,所以没时间来更新博客。趁着还没在下个版本来临之前,来这边再更新更新。是之前学习到的一些老知识点,就当来巩固一下了。开心QAQ

    今天给大家介绍的是--Pexpect

    Expect 程序主要用于人机对话的模拟
        1.运行程序 
        2.程序要求人的判断和输入 
        3.Expect 通过关键字匹配 
        4.根据关键字向程序发送符合的字符串 

    基本使用流程

    基本使用流程
        1.首先用 spawn 来执行一个程序 
        2.然后用 expect 来等待指定的关键字,这个关键字是被执行的程序打印到标准输出上面的 
        3.最后当发现这个关键字以后,根据关键字用 send 方法来发送字符串给这个程序 

    以下就是代码了,比较简单。但很实用

    #-*- coding:utf-8 -*-
    """
    This runs a command on a remote host using SSH. At the prompts enter hostname,
    user, password and the command.
    """
     
    import pexpect
    import getpass, os
     
    #user: ssh 主机的用户名
    #host:ssh 主机的域名
    #password:ssh 主机的密码
    #command:即将在远端 ssh 主机上运行的命令
    def ssh_command (user, host, password, command):
        """
        This runs a command on the remote host. This could also be done with the
        pxssh class, but this demonstrates what that class does at a simpler level.
        This returns a pexpect.spawn object. This handles the case when you try to
        connect to a new host and ssh asks you if you want to accept the public key
        fingerprint and continue connecting.
        """
        ssh_newkey = 'Are you sure you want to continue connecting'
        # 为 ssh 命令生成一个 spawn 类的子程序对象.
        child = pexpect.spawn('ssh -l %s %s %s'%(user, host, command))
        i = child.expect([pexpect.TIMEOUT, ssh_newkey, 'password: '])
        # 如果登录超时,打印出错信息,并退出.
        if i == 0: # Timeout
            print 'ERROR!'
            print 'SSH could not login. Here is what SSH said:'
            print child.before, child.after
            return None
        # 如果 ssh 没有 public key,接受它.
        if i == 1: # SSH does not have the public key. Just accept it.
            child.sendline ('yes')
            child.expect ('password: ')
            i = child.expect([pexpect.TIMEOUT, 'password: '])
            if i == 0: # Timeout
                print 'ERROR!'
                print 'SSH could not login. Here is what SSH said:'
                print child.before, child.after
            return None
        # 输入密码.
        child.sendline(password)
        return child
     
    def main ():
        # 获得用户指定 ssh 主机域名.
        host = '10.240.176.172'
        # 获得用户指定 ssh 主机用户名.
        user = 'root'
        # 获得用户指定 ssh 主机密码.
        password = 'tester'
        # 获得用户指定 ssh 主机上即将运行的命令.
        command = 'ls -a /home'
        child = ssh_command (user, host, password, command)
        # 匹配 pexpect.EOF
        child.expect(pexpect.EOF)
        # 输出命令结果.
        print child.before
     
    if __name__ == '__main__':
        try:
            main()
        except Exception, e:
            print str(e)
            #traceback.print_exc()
            os._exit(1)

    需要注意的知识点:

    spawn() 方法用来执行一个程序,打开一个到 (user, host, command) 服务器的 ssh 连接
    spawn() ,或者说 pexpect 并不会转译任何特殊字符
    process = pexpect.spawn('/bin/bash –c "ls –l | grep LOG > log_list.txt"')  or 
    cmd = "ls –l | grep LOG > log_list.txt"
    process = pexpect.spawn("/bin/bash", ["-c", cmd])
    process.expect(pexpect.EOF)
    
    timeout - 超时时间
    默认值: 30 (单位:秒)
    
    maxread - 缓存设置
    默认值: 2000 (单位:字符)
    指定一次性试着从命令输出中读多少数据。如果设置的数字比较大,那么从 TTY 中读取数据的次数就会少一些。
    设置为 1 表示关闭读缓存
    
    logfile - 运行输出控制
    默认值: None
    process = pexpect.spawn("ftp sw-tftp", logfile=sys.stdout) 如果你想看到spawn过程中的输出,那么可以将这些输出写入到 sys.stdout
    process = pexpect.spawn("ftp sw-tftp")
    logFileId = open("logfile.txt", 'w')
    process.logfile = logFileId
    
    logfile_read - 获取标准输出的内容
    默认值: None
    记录执行程序中返回的所有内容,也就是去掉你发出去的命令,而仅仅只包括命令结果的部分:
    process.logfile_read = sys.stdout
    
    cwd - 指定命令执行的目录
    默认值: None 或者说 ./
    sendline("ls –l", cwd="/etc")   在 /etc 目录下执行 ls –l 命令
    expect() - 关键字匹配
    后面的匹配关键字是一个列表的话,就会返回一个数字表示匹配到了列表中第几个关键字,从 0 开始计算。
    index = process.expect([
        'Permission Denied',
        'Terminal type',
        'ftp>',
    ])
    if index == 0:
        print "Permission denied at host, can't login."
        process.kill(0)
    elif index == 1:
        print "Login ok, set up terminal type…"
        process.sendline('vty100')
        process.expect("ftp>")
    elif index == 2:
        print "Login Ok, please send your command"
        process.interact()
    0.权限不足,这可能是ftp服务器出现问题,或者没有这个帐号,或者其他什么情况,反正只要发现这种情况的话,我们就给用户提示一下,
    然后杀掉这个进程
    1.登陆成功,但还要用户指定终端模式才能真正使用,所以我们在代码中指定了 vty100 这种模式,然后看是不是能真正使用了
    2.还是登陆成功了,而且还可以直接输入命令操作 ftp 服务器了,于是我们提示用户,然后把操作权限交给用户
    
    另外有一种特殊情况,如果同时有2个被匹配到,那么怎么办?简单来说就是这样:
    原始流中,第一个被关键字匹配到的内容会被使用
    匹配关键字列表中,最左边的会被使用
    
    child.expect(['(?i)etc', '(?i)readme', pexpect.EOF, pexpect.TIMEOUT])
    前 2 个匹配都是大小写无关的,关键就是这个 (?i) 匹配规则,它相当于 re.IGNORE 或者 re.I 这个关键字
    
    send() - 发送关键字
    send() 作为3个关键操作之一,用来向程序发送指定的字符串,它的使用没什么特殊的地方,比如:
    
    process.expect("ftp>")
    process.send("by
    ")
    
    sendline() - 发送带回车符的字符串
    sendline() 和 send() 唯一的区别就是在发送的字符串后面加上了回车换行符,这也使它们用在了不同的地方:
    
    只需要发送字符就可以的话用send()
    如果发送字符后还要回车的话,就用 sendline()
    
    特殊变量
    pexpect.EOF - 匹配终止信号
    pexpect.TIMEOUT - 匹配超时信号
  • 相关阅读:
    ueditor 后端配置项没有正常加载,上传插件不能正常使用 UTF8 PHP
    dedecms 后台栏目全部展开 包括三级栏目
    修改DedeCMS图片上传路径命名规则的具体方法步骤
    dedecms织梦副栏目名称和链接调用
    当位于顶级栏目显示下级栏目,当位于二级栏目显示同级栏目,当位于三级目录,显示上级栏目
    织梦多个栏目arclist调用副栏目不显示的解决办法
    PL/SQL连接64位Oracle配置方法
    U盘分区之后如何恢复
    Myeclipse 的使用随笔
    eclipse和myeclipse的差别问题
  • 原文地址:https://www.cnblogs.com/eilinge/p/9705275.html
Copyright © 2011-2022 走看看