精华内容
下载资源
问答
  • Python:pexpect模块下载

    2018-08-15 22:43:43
    Python中的pexpect模块下载Python中的pexpect模块下载
  • 背景介绍 ...因为这种情况特别多而且繁琐,所以很多语言都有各种自己的实现。最初的第一个 Expect 是由 TCL 语言实现的,所以后来的 Expect 都大致参考了最初的用法和流程,整体来说大致的流程包括: ...
  • pexpect模块

    2011-12-01 08:41:05
    很好的工具包
  • python之pexpect模块

    千次阅读 多人点赞 2020-03-21 16:51:16
    python之pexpect模块一:pexpect简介二:基本使用流程三:API使用3.1 spawn类3.2 expect()方法3.3 sendline()方法3.4 其他发送信息的方法3.5 其他获取结果的方法四:应用案例五:SSH专用类 一:pexpect简介 以下演示...

    一:pexpect简介

    以下演示python版本:python3.7.4
    pexpect官方文档:pexpect链接

    Expect 程序主要用于人机对话的模拟,就是那种系统提问,人来回答 yes/no ,或者账号登录输入用户名和密码等等的情况。因为这种情况特别多而且繁琐,所以很多语言都有各种自己的实现。最初的第一个 Expect 是由 TCL 语言实现的,所以后来的 Expect 都大致参考了最初的用法和流程,整体来说大致的流程包括:

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

    TCL 语言实现的 Expect 功能非常强大,我曾经用它实现了防火墙设备的完整测试平台。也因为它使用方便、范围广,几乎所有脚本语言都实现了各种各样的类似与Expect的功能,它们叫法虽然不同,但原理都相差不大

    pexpect 是 Python 语言的类 Expect 实现。从我的角度来看,它在功能上与 TCL 语言的实现还是有一些差距,比如没有buffer_full 事件、比如没有 expect before/after 事件等,但用来做一般的应用还是足够了。

    二:基本使用流程

    pexpect 的使用说来说去,就是围绕3个关键命令做操作:

    1. 首先用 spawn 来执行一个程序
    2. 使用 expect 来等待指定的关键字,这个关键字是被执行的程序打印到标准输出上面的
    3. 最后当发现这个关键字以后,根据关键字用 send 方法来发送字符串给这个程序
      第一步只需要做一次,但在程序中会不停的循环第二、三步来一步一步的完成整个工作。掌握这个概念之后 pexpect 的使用就很容易了。当然 pexpect 不会只有这 3 个方法,实际上还有很多外围的其他方法
    # 在本机执行命令,并输出命令执行结果
    import pexpect
    child = pexpect.spawn('ls -l')
    child.expect(pexpect.EOF)
    result = child.before.decode()
    print(result)
    

    三:API使用

    3.1 spawn类

    spawn() 方法用来执行一个程序,它返回这个程序的操作句柄,以后可以通过操作这个句柄来对这个程序进行操作。spawn类的__init__方法如下:

    class spawn(SpawnBase):
        '''This is the main class interface for Pexpect. Use this class to start
        and control child applications. '''
    
        # This is purely informational now - changing it has no effect
        use_native_pty_fork = use_native_pty_fork
    
        def __init__(self, command, args=[], timeout=30, maxread=2000,
                     searchwindowsize=None, logfile=None, cwd=None, env=None,
                     ignore_sighup=False, echo=True, preexec_fn=None,
                     encoding=None, codec_errors='strict', dimensions=None,
                     use_poll=False):
    

    上面第二节演示的就是spawn()第一个参数command的使用,变量child就是 spawn() 的程序操作句柄了,之后对这个程序的所有操作都是基于这个句柄的,所以它可以说是最重要的部分。
    command参数也可以配合args参数使用:

    child = pexpect.spawn('ls', args = ['-l', '/'])
    child.expect(pexpect.EOF)
    result = child.before.decode()
    print(result)
    

    注意:command参数不支持直接使用管道,通配符,标志输入,输出,错误重定向,如要使用就必须配合args参数

    child = pexpect.spawn('/bin/bash', ['-c', 'cat test|grep green'])
    child.expect(pexpect.EOF)
    result = child.before.decode()
    print(result)
    

    timeout参数:设置超时时间,单位为秒
    maxread参数:从TTY读取信息最大缓冲区
    logfile=None:指定日志文件,可指定为sys.stdout
    cwd=None:指定命令运行的目录,默认值 None 或者说 ./
    env=None:命令运行时的环境变量
    encoding=None:命令运行时的编码
    codec_errors=‘strict’:编码转换时的选项

    child = pexpect.spawn('ls -l', logfile=sys.stdout, cwd = '/home')
    child.expect(pexpect.EOF)
    

    3.2 expect()方法

    当 spawn() 启动了一个程序并返回程序控制句柄后,就可以用 expect() 方法来等待指定的关键字了。它最后会返回 0 表示匹配到了所需的关键字,如果后面的匹配关键字是一个列表的话,就会返回一个数字表示匹配到了列表中第几个关键字,从 0 开始计算。
    expect() 利用正则表达式来匹配所需的关键字。使用方式如下:

    # pattern_list   正则表达式列表,表示要匹配这些内容
    # timeout        不设置或者设置为-1的话,超时时间就采用self.timeout的值,默认是30秒。也可以自己设置。
    # searchwindowsize  功能和 spawn 上的一样,但是!请注意这个但是!下面会实际说明
    child.expect(pattern_list, timeout=-1, searchwindowsize=None)
    

    patter_list:可以为字符串,正则表达式,EOF,TIMEOUT,或者以上类型的列表,用以匹配子命令返回的结果。从子命令返回结果中进行匹配,若只提供字符串等非列表,匹配成功返回0;若提供列表,则返回匹配成功的列表序号;匹配失败,抛出异常
    searchwindowsize:是在 expect() 方法中真正生效的,默认情况下是 None,也就是每从子进程中获取一个字符就做一次完整匹配,如果子进程的输出很多的话……性能会非常低。如果设置为其他的值,表示从子进程中读取到多少个字符才做一次匹配,这样会显著减少匹配的次数,增加性能。

    child = pexpect.spawn('ls -l ./')
    child.expect('run')				# 匹配run字符 
    

    before/after/match:获取程序运行输出
    当 expect() 过程匹配到关键字(或者说正则表达式)之后,系统会自动给3个变量赋值,分别是 before, after 和 match

    before - 保存了到匹配到关键字为止,缓存里面已有的所有数据。也就是说如果缓存里缓存了 100 个字符的时候终于匹配到了关键字,那么 before 就是除了匹配到的关键字之外的所有字符
    after - 保存匹配到的关键字,比如你在 expect 里面使用了正则表达式,那么表达式匹配到的所有字符都在 after 里面
    match - 保存的是匹配到的正则表达式的实例,和上面的 after 相比一个是匹配到的字符串,一个是匹配到的正则表达式实例
    如果 expect() 过程中发生错误,那么 before 保存到目前位置缓存里的所有数据, after 和 match 都是 None

    child = pexpect.spawn('ls -l ./')
    child.expect('run')
    
    print(child.before)
    print(child.match)
    print(child.after)
    

    python之pexpect模块
    expect 方法中也可以传入一个列表,列表中的每个元素都是一个关键字的正则表达式

    child = pexpect.spawn('ls -l ./')
    index = child.expect(['test', 'run'])	# 匹配到列表中任意一个元素即停止匹配
    print(index)							# 返回列表中匹配到的字符索引
    

    如果没有匹配到任何字符则抛出异常:

    child = pexpect.spawn('ls -l ./')
    child.expect('who')
    

    异常信息如下:

    pexpect.exceptions.EOF: End Of File (EOF). Exception style platform.
    <pexpect.pty_spawn.spawn object at 0x7f101f7b4550>
    command: /bin/ls
    args: ['/bin/ls', '-l', './']
    buffer (last 100 chars): ''
    before (last 100 chars): 'rw-r--r-- 1 root root  3731 Mar 20 04:21 run.py\r\n-rw-r--r-- 1 root root   178 Mar 20 22:36 test.py\r\n'
    after: <class 'pexpect.exceptions.EOF'>
    match: None
    match_index: None
    exitstatus: 0
    flag_eof: True
    pid: 7785
    child_fd: 5
    closed: False
    timeout: 30
    delimiter: <class 'pexpect.exceptions.EOF'>
    logfile: None
    logfile_read: None
    logfile_send: None
    maxread: 2000
    ignorecase: False
    searchwindowsize: None
    delaybeforesend: 0.05
    delayafterclose: 0.1
    delayafterterminate: 0.1
    searcher: searcher_re:
        0: re.compile('who')
    

    可以匹配异常,让异常不在终端显示,从而程序不退出运行:

    child = pexpect.spawn('ls -l ./')
    child.expect(pexpect.EOF)			# 如果将此行代码打印的话会输出0
    
    child = pexpect.spawn('ls')
    child.expect(['run', pexpect.EOF])	# 如果返回1说明匹配到了异常
    

    匹配时自动应用re.DOTALL正则选项。(.+ 匹配所有字符,.* 返回空字符),匹配行尾使用 ‘\r\n’,无法用$匹配行尾

    3.3 sendline()方法

    sendline() - 发送带回车符的字符串
    sendline() 和 send() 唯一的区别就是在发送的字符串后面加上了回车换行符,这也使它们用在了不同的地方:

    1. 只需要发送字符就可以的话用send()
    2. 如果发送字符后还要回车的话,就用 sendline()

    它也会返回发送的字符数量

    child = pexpect.spawn('nslookup')
    child.expect('>')
    child.sendline('www.baidu.com')
    child.expect('>')
    print(child.before)
    child.sendline('exit')
    

    3.4 其他发送信息的方法

    send() :发送关键字
    send() 作为3个关键操作之一,用来向程序发送指定的字符串,末尾不带回车换行符

    process.expect("ftp>")
    process.send("by\n")
    # 这个方法会返回发送字符的数量
    

    sendcontrol():发送控制信号
    sendcontrol() 向子程序发送控制字符,比如 ctrl+C 或者 ctrl+D 之类的,比如你要向子程序发送 ctrl+G,那么就这样写:

    child.sendcontrol('g')
    

    sendeof() :发送 EOF 信号
    向子程序发送 End Of File 信号,一般用于确认上一次发送内容缓冲结束

    sendintr():发送终止信号
    向子程序发送 SIGINT 信号,相当于 Linux 中的 kill 2 ,它会直接终止掉子进程

    write():发送字符串
    类似于send()命令,只不过不会返回发送的字符数。

    writelines():发送包含字符串的列表
    类似于 write() 命令,只不过接受的是一个字符串列表, writelines() 会向子程序一条一条的发送列表中的元素,但是不会自动在每个元素的最后加上回车换行符。
    与 write() 相似的是,这个方法也不会返回发送的字符数量。

    3.5 其他获取结果的方法

    expect_exact():精确匹配
    它的使用和 expect() 是一样的,唯一不同的就是它的匹配列表中不再使用正则表达式。
    从性能上来说 expect_exact() 要更好一些,因为即使你没有使用正则表达式而只是简单的用了几个字符 expect() 也会先将它们转换成正则表达式模式然后再搜索,但 expect_exact() 不会,而且也不会把一些特殊符号转换掉。

    expect_list():预转换匹配
    使用方式和 expect() 一样,唯一不同的就是匹配列表只用已编译正则表达式和EOF, TIMEOUT;提高匹配速度;expect()方法是通过它工作的。
    expect() 稍微有点笨,每调用一次它都会将内部的正则表达式转换一次(当然也有其他办法避免),如果你是在以后循环中调用 expect() 的话,多余的转换动作就会降低性能,在这种情况下建议用 expect_list() 来代替。

    # timeout 为 -1 的话使用 self.timeout 的值
    # searchwindowsize 为 -1 的话,也使用系统默认的值
    child.expect_list(pattern_list, timeout=-1, searchwindowsize=-1)
    

    expect_loop()
    用于从标准输入中获取内容,loop这个词代表它会进入一个循环,必须要从标准输入中获取到关键字才会往下继续执行。

    expect_loop(self, searcher, timeout=-1, searchwindowsize=-1)
    

    read():返回剩下的所有内容
    获取子程序返回的所有内容,一般情况下我们可以用 expect 来期待某些内容,然后通过 before 这样的方式来获取,但这种方式有一个前提:那就是必须先 expect 某些字符,然后才能用 before 来获取缓存中剩下的内容。

    read() 的使用很不同,它期待一个 EOF 信号,然后将直到这个信号之前的所有输出全部返回,就像读一个文件那样。
    一般情况下,交互式程序只有关闭的时候才会返回 EOF ,比如用 by 命令关闭 ftp 服务器,或者用 exit 命令关闭一个 ssh 连接。
    这个方法使用范围比较狭窄,因为完全可以用 expect.EOF 方式来代替。当然如果是本机命令,每执行完一次之后都会返回 EOF ,这种情况下倒是很有用:

    child = pexpect.spawn('ls –l')
    output = child.read()
    print output
    

    可以用指定 read(size=-1) 的方式来设置返回的字符数,如果没有设置或者设置为负数则返回所有内容,正数则返回指定数量的内容,返回的内容是字符串形式。

    readline():返回一行输出
    返回一行输出,返回的内容包括最后的\r\n字符。
    也可以设置 readline(size=-1) 来指定返回的字符数,默认是负数表示返回所有的。

    readlines():返回列表模式的所有输出
    返回一个列表,列表中的每个元素都是一行(包括\r\n字符)。

    四:应用案例

    1:远程登录主机并执行命令

    child = pexpect.spawn('ssh ginvip@172.17.2.117')
    child.logfile = sys.stdout
    
    child.expect('password')
    child.sendline('ginvip')
    child.expect('ginvip')
    child.sendline('ls /')
    child.expect('ginvip')
    child.sendline('exit')
    

    如果要将日志写入文件:

    child = pexpect.spawn('ssh ginvip@172.17.2.117')
    fout = file('log.txt', 'w')
    child.logfile = fout
    child.expect('password')
    child.sendline('ginvip')
    child.expect('ginvip')
    child.sendline('ls /')
    child.expect('ginvip')
    child.sendline('exit')
    

    2:FTP文件管理

    import pexpect, sys, os, re, time
    def login_ftp():
        ftp = pexpect.spawn('ftp', cwd = cwd)
        if ftp.expect(prmpt) != 0:
            sys.exit()
        ftp.sendline('open {ip} {port}'.format(ip = ip, port = port))
        if ftp.expect('Name') != 0:
            sys.exit()
        ftp.sendline(username)
        if ftp.expect('Password:') != 0:
            sys.exit()
        ftp.sendline(password)
        if ftp.expect('230') != 0 or ftp.expect(prmpt) != 0:
            sys.exit()
        return ftp
    
    def get_server_files(ftp):
        ftp.sendline('ls')
        if ftp.expect('226') != 0:
            sys.exit()
        file_list = ftp.before
        file_list = file_list.split('\n')
        remtch = re.compile('\s+')
        file_list = [remtch.subn(' ', item.strip('\r'))[0] for item in file_list if 'group' in item]
        file_dict = dict()
        for item in file_list:
            datas = item.split(' ')
            file_dict[datas[-1]] = {'mon': week.index(datas[-4]) + 1, 'day': int(datas[-3]), 'time': datas[-2]}
        return file_dict
    
    def get_local_files():
        local_files = os.listdir(cwd)
        local_files_dict = dict()
        for file in local_files:
            t = time.ctime(os.stat(os.path.join(cwd, file)).st_mtime)
            datas = t.split(' ')
            local_files_dict[file] = {'mon': week.index(datas[-4]) + 1, 'day': int(datas[-3]), 'time': datas[-2][:5]}
        return local_files_dict
    
    def sync_files(ftp, local_files, remote_files):
        add_file = []
        for file in local_files.keys():
            if file not in remote_files:
                add_file.append(file)
            if file in remote_files:
                if local_files[file]['mon'] > remote_files[file]['mon']:
                    add_file.append(file)
        if add_file:
            for f in add_file:
                ftp.sendline('put' + f)
                if ftp.expect(['226', pexpect.EOF]) == 0:
                    print('upload success: ', f)
                else:
                    sys.exit()
        # 以下代码会删除FTP服务器上的文件,测试请慎重
        # delete_files = set(remote_files.keys()) - set(local_files.keys())
        # if delete_files:
        #     for f in delete_files:
        #         ftp.sendline('delete' + f)
        #         if ftp.expect(['250', pexpect.EOF]) == 0:
        #             print('delete success: ', f)
        #         else:
        #             print('Permision denied')
        #             sys.exit()
    
    def exit_ftp(ftp):
        if ftp:
            ftp.sendcontrol('d')
            print(ftp.read().decode())
    
    if __name__ == '__main__':
        week = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')
        cwd = '/root/backup'
        prmpt = ['ftp>', pexpect.EOF]
        ip = '172.17.2.76'
        port = '2121'
        username = 'xxxxx'
        password = 'xxxxxx'
    
        ftp = login_ftp()
        remote_files = get_server_files(ftp)
        print(remote_files)
        print('=' * 50)
        local_files = get_local_files()
        print(local_files)
        exit_ftp(ftp)
    

    五:SSH专用类

    pxssh类:为建立SSH连接定制了一些功能
    第一次连接时可以自动接受远程认证,可以自动应用公钥登录而不用输入密码
    构造方法参数除无CMD参数外其余与spawn类相同

    # 远程登录主机执行命令
    from pexpect.pxssh import pxssh
    hostname = '172.17.2.117'
    user = 'ginvip'
    password = 'ginvip'
    s = pxssh()
    s.login(hostname, user, password)
    s.sendline('ip addr')
    s.prompt()				# 匹配命令提示符
    print(s.before)			# 查看命令执行结果
    s.logout()
    

    实例:逐个登录指定的多台远程主机,监控远程主机并依据相关信息要求用户处理

    from pexpect.pxssh import pxssh
    import pexpect
    
    def login_host(host):
        ssh = pxssh()
        if ssh.login(host[0], host[1], host[2]):
            return ssh
    
    def get_cpu_num(ssh):
        ssh.sendline('cat /proc/cpuinfo')
        res = ssh.expect(['cpu cores.*\r\n', pexpect.EOF])
        if res == 0:
            data = ssh.after.split('\r\n')[0]
            data = data[data.index(':') + 1:]
            cpu_cores = int(data)
            ssh.prompt()
            return cpu_cores
    
    def get_cpu_load(ssh):
        ssh.sendline('uptime')
        if ssh.prompt():
            data = ssh.before
            data = data.strip('\r\n')
            data = data[data.rfind(':')+1:]
            data = data.split(',')
            return (float(data[0]), float(data[1]), float(data[2]))
    
    def get_cpu_stat(ssh):
        ssh.sendline('vmstat')
        ssh.prompt()
        print(ssh.before)
    
    def user_deal(host, file_name):
        s = login_host(host)
        if not s:
            print('Login failed: ', host[0])
            return
        try:
            cpu_cores = get_cpu_num(s)
            if not cpu_cores:
                print('Do not get cpu cores: ', host[0])
                return
            cpu_load = get_cpu_load(s)
            if cpu_load[2] >= cpu_cores:
                get_cpu_stat(s)
                print('system is not healthy. Do you want to deal? (yes/no)')
                yn = input()
                if yn == 'yes':
                    with open(file_name, 'ab+') as f:
                        s.logfile = f
                        s.interact()
                        s.prompt()
                        s.logfile = None
            else:
                print('system is healthy: ', host[0])
        except Exception as e:
            print('failed: ', host[0])
        finally:
            s.logout()
    
    if __name__ == '__main__':
        hosts = [('172.17.2.117', 'root', 'root')]
        file_name = 'log.txt'
        for host in hosts:
            user_deal(host, file_name)
    
    展开全文
  • 下面介绍的代码,是使用python的pexpect模块实现的: 代码 import os import sys import pexpect import datetime #获取昨天的日期 date_yes = (datetime.date.today()-datetime.timedelta(days=1)).strftime('%Y%m...
  • Pexpect模块使用

    2020-12-29 21:50:44
    1 Pexpect的作用 pexpect 是 Python 语言的类 Expect 实现,Expect 程序主要用于人机对话的模拟,就是那种系统提问,人来回答 yes/no ,或者账号登录输入用户名和密码等等的情况。 Pexpect能够产生子应用程序并控制...

    1 Pexpect的作用

    pexpect 是 Python 语言的类 Expect 实现,Expect 程序主要用于人机对话的模拟,就是那种系统提问,人来回答 yes/no ,或者账号登录输入用户名和密码等等的情况。

    Pexpect能够产生子应用程序并控制他们,能够通过期望模式对子应用的输出做出反应。
    Pexpect允许你的脚本产生子应用、控制他们像一个人类在输入命令一样,Pexcept人机模拟对话的大致过程:

    1、 运行程序
    2、 程序要求人的判断和输入
    3、 Expect 通过关键字匹配
    4、 根据关键字向程序发送符合的字符串

    Pexpect的主要特点是需要Python的基本库pty,这个库只有在类Unix系统上才有

    2 使用Pexpect的场景

    Pexpect使用在自动交互的应用,例如SSH、SFTP、PASSWD、TELNET。
    它可以被应用在使用自动设置脚本为不同的服务器自动地重复的安装软件包。也可以被应用在自动的软件测试。

    3 Pexpect的使用

    第1步只需要做一次,但在程序中会不停的循环第2、3步来一步一步的完成整个工作:

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

    4 pexpect.spawn类何pexpect.spawnu类

    原型:class pexpect.spawn(command, args=[], timeout=30, maxread=2000, searchwindowsize=None, logfile=None, cwd=None, env=None, ignore_sighup=False, echo=True, preexec_fn=None, encoding=None, codec_errors=‘strict’, dimensions=None, use_poll=False)

    pexpect.spawn与pexpect.spawnu的区别在于前者的启动程序的运行输出为bytes类型,而后者为str字符串类型。

    spawn是Pexpect的主类接口,使用此类来启动和控制子应用程序,它返回这个程序的操作句柄(pexpect.pty_spawn.spawn object),以后可以通过操作这个句柄来对这个程序进行操作

    child = pexpect.spawn('python')  # 其中child就是新启动的python解释器的操作句柄
    
    • command

    可以是包含命令和该命令的任何参数的字符串

    Pexpect不会解释任何特殊字符(如:shell原始字符 >,| 或 *),如果需要运行一个命令并将结果传送给另一个命令,要启动一个shell, EX:

    child = pexpect.spawn('/bin/bash -c "ls -l | grep LOG > logs.txt"')
    child.expect(pexpect.EOF)
    
    • timeout - 超时时间
      指定程序的默认超时时间。程序被启动之后会有输出,也会在脚本中检查输出中的关键字是否是已知并处理的,如果指定时间内没找到程序就会出错返回

    4.1 expect方法

    原型:expect(pattern, timeout=-1, searchwindowsize=-1, async_=False, **kw)
    在流中进行搜索,直到匹配到期望的模式为止,返回匹配pattern在pattern列表中索引。

    • pattern

    指定要匹配的模式,可以是字符串、EOF、a compiled re类型,或者这些类型组成的列表,其中字符串会被编译成re type
    如果pattern不是列表,则expect方法在匹配后返回0。
    可将 pexcept.EOF 或 pexcept.TIMEOUT增加到pattern列表,这将导致期望匹配EOF或TIMEOUT条件,而不是引发异常

    index = p.expect(['good', 'bad', pexpect.EOF, pexpect.TIMEOUT])
    if index == 0:
        do_something()
    elif index == 1:
        do_something_else()
    elif index == 2:
        do_some_other_thing()
    elif index == 3:
        do_something_completely_different()
    

    替代如下代码:

    try:
        index = p.expect(['good', 'bad'])
        if index == 0:
            do_something()
        elif index == 1:
            do_something_else()
    except EOF:
        do_some_other_thing()
    except TIMEOUT:
        do_something_completely_different()
    
    • timeout
      指定期望匹配的超时时间,超时则匹配结束。

    为默认值(即-1)时,expect方法会使用pexpect.spawn的timeout,超过即抛出TIMEOUT异常
    如果指定了timeout为正数,则使用expect方法自己指定的timeout: 匹配操作超时,抛出TIMEOUT异常
    为None则会陷入无限等待阻塞状态

    In [15]: child = pexpect.spawn('python')                                                                                    
    
    In [16]: child.expect('>>>> ', timeout=10)  
    
    # output
    '''
    ...
    TIMEOUT: Timeout exceeded.
    <pexpect.pty_spawn.spawn object at 0x7f559ba035f8>
    command: /usr/bin/python
    ...
    '''
    
    • async_

    在Python 3.4或安装了asyncio的Python 3.3上,传递async_ = True将使此返回asyncio协程,您可以从中获得协程,以得到与该方法通常直接给出的结果相同的结果。

    4.2 sendline(s=’’)方法

    打包send方法,将字符串s发送给子进程,会自动增加行分隔符(windows:’\r\n’, linux:’\n’)

    4.3 before/after/match/buffer - 获取程序运行输出

    当 expect() 过程匹配到关键字(或者说正则表达式)之后,系统会自动给3个变量赋值,分别是 before, after 和 match

    • before

    保存上一次 expect 匹配之后,除掉匹配到的关键字本身,系统缓存中剩余下来的全部内容

    保存了到匹配到关键字为止,buffer缓存里面已有的所有数据。也就是说如果buffer缓存里缓存了 100 个字符的时候终于匹配到了关键字,那么 before 就是除了匹配到的关键字之前的所有字符

    如果 expect() 过程中发生错误,那么 before 保存到目前位置缓存里的所有数据, after 和 match 都是 None

    • after

    保存匹配到的关键字,比如你在 expect 里面使用了正则表达式,那么表达式匹配到的所有字符都在 after 里面

    import pexpect
    
    analyzer = pexpect.spawnu('python')
    for newWord in ['print(1)', 'print(2)']:
        index = analyzer.expect('>>> ')
        print(f'before:{analyzer.before}')
        print(f'after:{analyzer.after}')
        analyzer.sendline(newWord )
    
    # output
    '''
    before:Python 2.7.17 (default, Sep 30 2020, 13:38:04) 
    [GCC 7.5.0] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    
    after:>>> 
    before:print(1)
    1
    
    after:>>> 
    '''
    
    • match
      保存的是匹配到的正则表达式的实例,和上面的 after 相比一个是匹配到的字符串,一个是匹配到的正则表达式实例

    • buffer

    pexpect 中的 buffer 是一个关键,但又不能被直接操作的变量,它保存的是运行过程中每一个 expect 之后的所有内容,随时被更新。而 before/after 都是直接源于它的,而 expect 的关键字匹配本身也是在 buffer 中做匹配的。

    正因为它的重要性,对这个变量中的内容需要特别的警惕。比如我们将登陆设备,发送命令,退出设备这3个步骤写进3个函数的时候,最好保证每个步骤都不会影响下一个步骤,在每个步骤开始的时候,最好做清空操作:handle.buffer = ‘’

    In [97]: child = pexpect.spawn('python')                                                                                    
    
    In [98]: child.expect(['>>>> ',pexpect.TIMEOUT], timeout=5)                                                                 
    Out[98]: 1
    
    In [99]: child.buffer    # 没有匹配成功,则输出仍在buffer中                                                                                                   
    Out[99]: b'Python 2.7.17 (default, Sep 30 2020, 13:38:04) \r\n[GCC 7.5.0] on linux2\r\nType "help", "copyright", "credits" or "license" for more information.\r\n>>> '
    
    In [100]: child.buffer = b'' # 清空buffer                                                                                           
    
    In [101]: child.sendline('print(11)')                                                                                       
    Out[101]: 10
    
    In [102]: child.expect(['>>> ',pexpect.TIMEOUT], timeout=5) # 匹配提示符,获取print(11)的输出结果                                                                 
    Out[102]: 0
    
    In [103]: child.before                                                                                                      
    Out[103]: b'print(11)\r\n11\r\n'
    
    In [104]: child.buffer                                                                                                      
    Out[104]: b''
    

    expect方法匹配失败则,输出数据仍保存在buffer中, 且before是buffer数据的复制:

    In [63]: child = pexpect.spawn('python')                                                                                    
    
    In [64]: child.expect(['xxx',pexpect.TIMEOUT], timeout=5)     # 置匹配失败                                                              
    Out[64]: 1
    
    In [65]: child.buffer # python命令的输出在buffer中,且before有同样的数据                                                                                                       
    Out[65]: b'Python 2.7.17 (default, Sep 30 2020, 13:38:04) \r\n[GCC 7.5.0] on linux2\r\nType "help", "copyright", "credits" or "license" for more information.\r\n>>> '
    
    In [66]: child.before                                                                                                       
    Out[66]: b'Python 2.7.17 (default, Sep 30 2020, 13:38:04) \r\n[GCC 7.5.0] on linux2\r\nType "help", "copyright", "credits" or "license" for more information.\r\n>>> '
    

    expect方法匹配成功时,会将到匹配位置之前的所有数据保存到before属性,并将匹配信息保存到after属性中,如果匹配位置之后仍有数据则继续保留在buffer中:

    In [67]: child.sendline("print(11)")                                                                                        
    Out[67]: 10
    
    In [68]: child.expect(['xxx',pexpect.TIMEOUT], timeout=5)                                                                   
    Out[68]: 1
    
    In [69]: child.buffer                                                                                                       
    Out[69]: b'Python 2.7.17 (default, Sep 30 2020, 13:38:04) \r\n[GCC 7.5.0] on linux2\r\nType "help", "copyright", "credits" or "license" for more information.\r\n>>> print(11)\r\n11\r\n>>> '   # print(11)命令的输出附加在已有数据之后
    
    In [70]: child.before                                                                                                       
    Out[70]: b'Python 2.7.17 (default, Sep 30 2020, 13:38:04) \r\n[GCC 7.5.0] on linux2\r\nType "help", "copyright", "credits" or "license" for more information.\r\n>>> print(11)\r\n11\r\n>>> '
    
    In [71]: child.expect(['>>> ',pexpect.TIMEOUT], timeout=5)       # 正确匹配python交互界面的'>>> '提示符                                                           
    Out[71]: 0
    
    In [72]: child.buffer                                                                                                          
    Out[72]: b'print(11)\r\n11\r\n>>> '  # 一串'>>> '之前的数据被从buffer中清除,并保存到before中
    
    In [73]: child.before  # 从buffer清除的被保存到before中:匹配'>>> '之前的数据部分                                                                                                     
    Out[73]: b'Python 2.7.17 (default, Sep 30 2020, 13:38:04) \r\n[GCC 7.5.0] on linux2\r\nType "help", "copyright", "credits" or "license" for more information.\r\n'
    

    match: 匹配到模式后,存储re.MatchObject匹配对象

    4.3 特殊变量

    • pexpect.EOF - 匹配终止信号

    EOF 变量使用范围很广泛,比如检查 ssh/ftp/telnet 连接是否终止啊,文件是否已经到达末尾啊。 pexpect 大部分脚本的最后都会检查 EOF 变量来判断是不是正常终止和退出,比如下面的代码:

    In [12]: child = pexpect.spawn('python')                                                                                    
    
    In [13]: child.sendline('exit()')        # 退出python解释器                                                                                   
    Out[13]: 7
    
    In [14]: child.expect(pexpect.EOF)  # 检测python解释器终止                                                                                         
    Out[14]: 0                          # 匹配到终止模式,说明已经终止
    
    • pexpect.TIMEOUT - 匹配超时信号

    TIMEOUT 变量用来匹配超时的情况,默认情况下 expect 的超时时间是 60 秒,如果超过 60 秒还没有发现期待的关键字,就会触发这个行为

    In [20]: child = pexpect.spawn('python')                                                                                    
    
    In [21]: child.timeout = 10       # 将所有expet方法的超时时间都设置为10s                                                                                          
    
    In [22]: child.expect(['>>>> ', pexpect.TIMEOUT])                                                                           
    Out[22]: 1
    

    参考

    Pexpect

    展开全文
  • 主要介绍了Python pexpect模块及shell脚本except原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • Python Pexpect 模块使用说明

    万次阅读 多人点赞 2017-11-30 18:58:45
    这个参数是 pexpect 3.1 开始引入的,在 3.1 之前(比如 pexpect 2.3),spawn 的子程序会过滤 SIGHUP 信号,也就是用 Ctrl+C 是不能终止子程序的,3.1的默认值也继承了这个行为,但是如果设置 ignore_sighup = ...
     

    背景介绍

    Expect 程序主要用于人机对话的模拟,就是那种系统提问,人来回答 yes/no ,或者账号登录输入用户名和密码等等的情况。因为这种情况特别多而且繁琐,所以很多语言都有各种自己的实现。最初的第一个 Expect 是由 TCL 语言实现的,所以后来的 Expect 都大致参考了最初的用法和流程,整体来说大致的流程包括:

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

    TCL 语言实现的 Expect 功能非常强大,我曾经用它实现了防火墙设备的完整测试平台。也因为它使用方便、范围广,几乎所有脚本语言都实现了各种各样的类似与Expect的功能,它们叫法虽然不同,但原理都相差不大

    pexpect 是 Python 语言的类 Expect 实现。从我的角度来看,它在功能上与 TCL 语言的实现还是有一些差距,比如没有buffer_full 事件、比如没有 expect before/after 事件等,但用来做一般的应用还是足够了。

    基本使用流程

    pexpect 的使用说来说去,就是围绕3个关键命令做操作:

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

    第一步只需要做一次,但在程序中会不停的循环第二、三步来一步一步的完成整个工作。掌握这个概念之后 pexpect 的使用就很容易了。当然 pexpect 不会只有这 3 个方法,实际上还有很多外围的其他方法,我们一个一个来说明

    API

    spawn() - 执行程序

    spawn() 方法用来执行一个程序,它返回这个程序的操作句柄,以后可以通过操作这个句柄来对这个程序进行操作,比如:

    process = pexpect.spawn('ftp sw-tftp')
    

    上面 spawn() 中的字符串就是要执行的程序,这里我们打开一个到 sw-tftp 服务器的 ftp 连接。 spawn() 中的第一个元素就是要执行的命令,除此之外还可以指定一些其他参数,比如: pexpect.spawn('ftp sw-tftp', timeout=60) 就指定了超时时间,这些具体的会在后面讲解。

    process 就是 spawn() 的程序操作句柄了,之后对这个程序的所有操作都是基于这个句柄的,所以它可以说是最重要的部分。尽量给它起个简短点的名字,不然后面的程序要多打不少字的。-

    注意: spawn() ,或者说 pexpect 并不会转译任何特殊字符 比如 | * 字符在Linux的shell中有特殊含义,但是在 pexpect 中不会转译它们,如果在 linux 系统中想使用这些符号的正确含义就必须加上 shell 来运行,这是很容易犯的一个错误。

    正确的方式:

    process = pexpect.spawn('/bin/bash –c "ls –l | grep LOG > log_list.txt"')
    process.expect(pexpect.EOF)
    

    spawn() 还有一种调用方式就是第一个参数是主程序,而下一个参数是主程序的参数,理解起来很麻烦?看看实际代码吧:

    cmd = "ls –l | grep LOG > log_list.txt"
    process = pexpect.spawn("/bin/bash", ["-c", cmd])
    process.expect(pexpect.EOF)
    

    这些代码和上面一个例子是相同的,是不是更清晰一些?

    spawn 的选项包括下面这些:

    timeout - 超时时间

    默认值: 30 (单位:秒)

    指定程序的默认超时时间。程序被启动之后会有输出,我们也会在脚本中检查输出中的关键字是否是已知并处理的,如果指定时间内没找到程序就会出错返回。

    maxread - 缓存设置

    默认值: 2000 (单位:字符)

    指定一次性试着从命令输出中读多少数据。如果设置的数字比较大,那么从 TTY 中读取数据的次数就会少一些。

    设置为 1 表示关闭读缓存。

    设置更大的数值会提高读取大量数据的性能,但会浪费更多的内存。这个值的设置与 searchwindowsize 合作会提供更多功能。

    缓存的大小并不会影响获取的内容,也就是说如果一个命令输出超过2000个字符以后,先前缓存的字符不会丢失掉,而是放到其他地方去,当你用 self.before (这里 self 代表 spawn 的实例)还是可以取到完整的输出的。

    searchwindowsize - 模式匹配阀值

    默认值: None

    searchwindowsize 参数是与 maxread 参数一起合作使用的,它的功能比较微妙,但可以显著减少缓存中有很多字符时的匹配时间。

    默认情况下, expect() 匹配指定的关键字都是这样:每次缓存中取得一个字符时就会对整个缓存中的所有内容匹配一次正则表达式,你可以想像如果程序的返回特别多的时候,性能会多么的低。

    设置 searchwindowsize 的值表示一次性收到多少个字符之后才匹配一次表达式,比如现在有一条命令会出现大量的输出,但匹配关键字是标准的 FTP 提示符 ftp> ,显然要匹配的字符只有 5 个(包括空格),但是默认情况下每当 expect 获得一个新字符就从头匹配一次这几个字符,如果缓存中已经有了 1W 个字符,一次一次的从里面匹配是非常消耗资源的,这个时候就可以设置 searchwindowsize=10, 这样 expect 就只会从最新的(最后获取的) 10 个字符中匹配关键字了,如果设置的值比较合适的话会显著提升性能。不用担心缓存中的字符是否会被丢弃,不管有多少输出,只要不超时就总会得到所有字符的,这个参数的设置仅仅影响匹配的行为。

    这个参数一般在 expect() 命令中设置, pexpect 2.x 版本似乎有一个 bug ,在 spawn 中设置是不生效的。

    logfile - 运行输出控制

    默认值: None

    当给 logfile 参数指定了一个文件句柄时,所有从标准输入和标准输出获得的内容都会写入这个文件中(注意这个写入是 copy 方式的),如果指定了文件句柄,那么每次向程序发送指令(process.send)都会刷新这个文件(flush)。

    这里有一个很重要的技巧:如果你想看到spawn过程中的输出,那么可以将这些输出写入到 sys.stdout 里去,比如:

    process = pexpect.spawn("ftp sw-tftp", logfile=sys.stdout)
    

    用这样的方式可以看到整个程序执行期间的输入和输出,很适合调试。

    还有一个例子:

    process = pexpect.spawn("ftp sw-tftp")
    logFileId = open("logfile.txt", 'w')
    process.logfile = logFileId
    

    注意: logfile.txt 文件里,既包含了程序运行时的输出,也包含了 spawn 向程序发送的内容,有的时候你也许不希望这样,因为某些内容出现了2次,那么还有 2 个很重要的 logfile 关联参数:

    logfile_read - 获取标准输出的内容

    默认值: None

    记录执行程序中返回的所有内容,也就是去掉你发出去的命令,而仅仅只包括命令结果的部分:

    process.logfile_read = sys.stdout
    

    上面的语句会在屏幕上打印程序执行过程中的所有输出,但是一般不包含你向程序发送的命令,不过大部分程序都有回显机制,比如发命令的时候设备不光接收到命令字符串,还会反向在你的终端上把字符串显示出来让你明白哪些字符被输入了,这种时候也是会被这个方法读到的。只有那些不会回显的情况 logfile_read 才会拿不到,比如输入密码的时候。

    logfile_send - 获取发送的内容
    默认值: None

    记录向执行程序发送的所有内容

    process.logfile_send = sys.stdout
    

    上面的语句仅仅在屏幕上打印向程序发送的内容。

    cwd - 指定命令执行的目录

    默认值: None 或者说 ./

    cwd 用来指定命令发送的命令在哪个路径下执行,它一般是用在 send() 系列命令中,比如在 Linux 中,你想在 /etc 目录下执行 ls –l 命令,那么完全不需要用 sendline("cd /etc && ls -l") 这样的方式,而是用 sendline("ls –l", cwd="/etc") 就可以了。

    env - 指定环境变量

    默认值: None

    指定环境变量的值,这个值是一个字典,如果你发送的命令要使用一些环境变量,那么可以在这里提供

    ignore_sighup - 是否过滤 SIGHUP 信号

    默认值: True

    这个参数是 pexpect 3.1 开始引入的,在 3.1 之前(比如 pexpect 2.3),spawn 的子程序会过滤 SIGHUP 信号,也就是用 Ctrl+C 是不能终止子程序的,3.1的默认值也继承了这个行为,但是如果设置 ignore_sighup = False 就可以改变这个行为。

    delaybeforesend - 字符发送延时

    默认值: 0.05

    这是一个隐藏参数用来设置发送字符串之前的延时。增加这个参数的最大理由是因为很多人碰见这样一个问题:

    在 FTP 程序中登录时如果用脚本输入密码时会直接显示出来。这是基于一个一般人不可思议的事实:当 FTP 登录时,实际上服务器会先打印要求你输入密码的提示符,然后再发一个信号把回显功能取消,当人使用键盘输入的时候因为这个动作延时比较高所以不可能看到回显的密码,但脚本会在发现输入密码的提示符时立即发送,于是密码就会在关闭回显之前出现了。 Pexpect 为了解决这个问题在每次发送字符前默认等待 50 毫秒,如果你认为不必要的话就可以自己设置为 0 来取消这个行为。

    expect() - 关键字匹配

    当 spawn() 启动了一个程序并返回程序控制句柄后,就可以用 expect() 方法来等待指定的关键字了。它最后会返回 0 表示匹配到了所需的关键字,如果后面的匹配关键字是一个列表的话,就会返回一个数字表示匹配到了列表中第几个关键字,从 0 开始计算。

    expect() 利用正则表达式来匹配所需的关键字。(正则表达式使用范围非常广,几乎所有语言都对它提供支持,如果不知道如何使用的话,可以参考我的另一份文档《正则表达式参考》)。

    它的使用方式:

    # pattern_list      正则表达式列表,表示要匹配这些内容
    # timeout           不设置或者设置为-1的话,超时时间就采用self.timeout的值,默认是30秒。也可以自己设置。
    # searchwindowsize  功能和 spawn 上的一样,但是!请注意这个但是!下面会实际说明
    process.expect(pattern_list, timeout=-1, searchwindowsize=None)
    

    在这里的 searchwindowsize 是在 expect() 方法中真正生效的,默认情况下是 None,也就是每从子进程中获取一个字符就做一次完整匹配,如果子进程的输出很多的话……性能会非常低。如果设置为其他的值,表示从子进程中读取到多少个字符才做一次匹配,这样会显著减少匹配的次数,增加性能。

    经过测试,对于一个有 48100000 个字符的子进程,将 searchwindowsize 设置为 2000 时,完全处理完成需要 73.2730 秒;同样的子进程将这个参数设置为 None 则需要 1949.6259 秒,Oh, my Lady GAGA…… 完全是指数上升啊。

    • 最简单的匹配方式

      process.expect('[Nn]ame')
      

      上面的代码表示:匹配 process 这个句柄(代表 spawn 方法的例子中我们启动的 ftp 连接)中的 name 关键字,其中 n 不分大小写。

      上面的关键字一旦匹配,就会返回0表示匹配成功,但是如果一直匹配不到呢?默认是会一直等下去,但是如果设置了 timeout 的话就会超时。

    • 匹配一系列输出

      实际上, expect() 可以匹配一系列输出,通过检查匹配到的输出,我们可以做不同的事情。比如之前 spawn 的 ftp 连接,如果我们输入用户名之后有不同的情况,就可以通过监控这些不同情况来做不同的动作,比如:

      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()
      

      上面的代码中,expect 方法中的是一个列表,列表中的每个元素都是一个关键字的正则表达式,也就是说我们期待这 3 种情况之一,而 expect 返回一个顺序值来代表我匹配到了哪一个元素(也就是发生了哪种情况了),这个顺序值是从 0 开始计算的。

      当expect之后,下面的 if 语句就开始处理这 3 种情况了:

      1. 权限不足,这可能是 ftp 服务器出现问题,或者没有这个帐号,或者其他什么情况,反正只要发现这种情况的话,我们就给用户提示一下,然后杀掉这个进程
      2. 登陆成功,但还要用户指定终端模式才能真正使用,所以我们在代码中指定了 vty100 这种模式,然后看是不是能真正使用了
      3. 还是登陆成功了,而且还可以直接输入命令操作 ftp 服务器了,于是我们提示用户,然后把操作权限交给用户

      另外有一种特殊情况,如果同时有2个被匹配到,那么怎么办?简单来说就是这样:

      1. 原始流中,第一个被关键字匹配到的内容会被使用
      2. 匹配关键字列表中,最左边的会被使用

      给个例子:

      # 如果流里面的内容是 "hello world"
      index = process.expect(["hi", "hello", "hello world"])
      

      返回的值是 1,也就是 'hello' 被匹配到了,哪怕真正最好的匹配是 "hello world" 但因为放在后面所以仍然无效。

    使用技巧

    1. 如果要检查或者匹配 expect.EOF 和 expect.TIMEOUT 这两种情形,那么必须将它们放进匹配列表里面去,这样可以通过检查返回的数字来处理它们。如果没放进列表的话,就会发生 EOF 或者 TIMEOUT 错误,程序就会中途停止了

    2. 匹配规则中有些特殊语法,比如下面的规则中前 2 个匹配都是大小写无关的,关键就是这个 (?i) 匹配规则,它相当于 re.IGNORE 或者 re.I 这个关键字,因为毕竟不是真正的正则表达式引擎,所以 pexpect 使用这样特殊语法:

      child.expect(['(?i)etc', '(?i)readme', pexpect.EOF, pexpect.TIMEOUT])
      

    expect_exact() - 精确匹配

    它的使用和 expect() 是一样的,唯一不同的就是它的匹配列表中不再使用正则表达式。

    从性能上来说 expect_exact() 要更好一些,因为即使你没有使用正则表达式而只是简单的用了几个字符 expect() 也会先将它们转换成正则表达式模式然后再搜索,但 expect_exact() 不会,而且也不会把一些特殊符号转换掉。

    expect_list() - 预转换匹配

    使用方式和 expect() 一样,唯一不同的就是它里面接受的正则表达式列表只会转换一次。

    expect() 稍微有点笨,每调用一次它都会将内部的正则表达式转换一次(当然也有其他办法避免),如果你是在以后循环中调用 expect() 的话,多余的转换动作就会降低性能,在这种情况下建议用 expect_list() 来代替。

    使用方法:

    # timeout 为 -1 的话使用 self.timeout 的值
    # searchwindowsize 为 -1 的话,也使用系统默认的值
    process.expect_list(pattern_list, timeout=-1, searchwindowsize=-1)
    

    expect_loop()

    用于从标准输入中获取内容,loop这个词代表它会进入一个循环,必须要从标准输入中获取到关键字才会往下继续执行。

    使用方法:

    expect_loop(self, searcher, timeout=-1, searchwindowsize=-1)
    

    send() - 发送关键字

    send() 作为3个关键操作之一,用来向程序发送指定的字符串,它的使用没什么特殊的地方,比如:

    process.expect("ftp>")
    process.send("by\n")
    

    这个方法会返回发送字符的数量。

    sendline() - 发送带回车符的字符串

    sendline() 和 send() 唯一的区别就是在发送的字符串后面加上了回车换行符,这也使它们用在了不同的地方:

    • 只需要发送字符就可以的话用send()
    • 如果发送字符后还要回车的话,就用 sendline()

    它也会返回发送的字符数量

    sendcontrol() - 发送控制信号

    sendcontrol() 向子程序发送控制字符,比如 <kbd>ctrl+C</kbd> 或者 <kbd>ctrl+D</kbd> 之类的,比如你要向子程序发送 <kbd>ctrl+G</kbd>,那么就这样写:

    process.sendcontrol('g')
    

    sendeof() - 发送 EOF 信号

    向子程序发送 End Of File 信号。

    sendintr() - 发送终止信号

    向子程序发送 SIGINT 信号,相当于 Linux 中的 kill 2 ,它会直接终止掉子进程。

    interact() - 将控制权交给用户

    interact() 表示将控制权限交给用户(或者说标准输入)。一般情况下 pexpect 会接管所有的输入和输出,但有的时候还是希望用户介入,或者仅仅是为了完成一部分工作的时候, interact() 就很有用了。

    比如:

    1. 登陆 ftp 服务器的时候,在输入用户密码阶段希望用户手工输入密码,然后脚本完成剩余工作时(将用户密码写在脚本中可不安全)
    2. 只希望完成登陆工作,比如要 ssh 连接到一台远方的服务器,但中间要经过好几跳,用手工输入实在太麻烦,所以就用脚本先跳到目的服务器上,然后再把控制权限还给用户做操作。

    使用方法:

    # escape_character 就是当用户输出这里指定的字符以后表示自己的操作完成了,将控制权重新交给 pexpect
    process.interact(escape_character='\x1d', input_filter=None, output_filter= None)
    

    详细来说,这个方法将控制权交给用户(或者说用户操作的键盘),然后简单的将标准输出、标准错误输出和标准输入绑定到系统上来。

    通过设置 escape_character 的值,可以定义返回码,默认是 <kbd>ctrl+]</kbd> 或者说 <kbd>^]</kbd>,当输入了返回码以后,脚本会将控制权从用户那里重新拿回来,然后继续向下执行。

    close() - 停止应用程序

    如果想中途关闭子程序,那么可以用 close 来完成,调用这个方法后会返回这个程序的返回值。

    如果设置 force=True 会强行关闭这个程序,大概的过程就是先发送 SIGHUP 和 SIGINT 信号,如果都无效的话就发 SIGKILL 信号,反正不管怎么样都会保证这个程序被关闭掉。

    多次调用这个方法是允许的,但是不保证每次都能返回正确的返回值。尽量不要这么做,如果想保证程序被关闭的话只要设置force的值就可以了。

    下面是实例:

    process.close(force=True)
    

    terminate() - 停止应用程序

    可以看作是上面 close() 的别名,因为不管是功能还是使用方法都是一样的。

    Kill() - 发送 SIGKILL 信号

    向子程序发送 SIGKILL 的信号。

    flush()

    什么都不干,只是为了与文件方法兼容而已。

    isalive() - 检查子程序运行状态

    检查被调用的子程序是否正在运行,这个方法是运行在非阻断模式下面的。

    如果获得的返回是 True 表示子程序正在运行;返回 False 则表示程序运行终止。

    isatty() - 检查是否运行在 TTY 设备上

    返回 True 表示打开和连接到了一个 tty 类型的设备,或者返回 False 表示未连接。

    next() - 返回下一行内容

    和操作文件一样,这个方法也是返回缓存中下一行的内容。

    read() - 返回剩下的所有内容

    获取子程序返回的所有内容,一般情况下我们可以用 expect 来期待某些内容,然后通过 process.before 这样的方式来获取,但这种方式有一个前提:那就是必须先 expect 某些字符,然后才能用 process.before 来获取缓存中剩下的内容。

    read() 的使用很不同,它期待一个 EOF 信号,然后将直到这个信号之前的所有输出全部返回,就像读一个文件那样。

    一般情况下,交互式程序只有关闭的时候才会返回 EOF ,比如用 by 命令关闭 ftp 服务器,或者用 exit 命令关闭一个 ssh 连接。

    这个方法使用范围比较狭窄,因为完全可以用 expect.EOF 方式来代替。当然如果是本机命令,每执行完一次之后都会返回 EOF ,这种情况下倒是很有用:

    process = pexpect.spawn('ls –l')
    output = process.read()
    print output
    

    看起来这么做有点无聊?但我想一定有什么理由支持这个方法。
    可以用指定 read(size=-1) 的方式来设置返回的字符数,如果没有设置或者设置为负数则返回所有内容,正数则返回指定数量的内容,返回的内容是字符串形式。

    readline() - 返回一行输出

    返回一行输出,返回的内容包括最后的\r\n字符。

    也可以设置 readline(size=-1) 来指定返回的字符数,默认是负数表示返回所有的。

    readlines() - 返回列表模式的所有输出

    返回一个列表,列表中的每个元素都是一行(包括\r\n字符)。

    setecho() - 子程序响应模式

    设置子程序运行时的响应方式,一般情况下向子程序发送字符的时候,这些字符都会在标准输出上显示出来,这样你可以看到你发送出去的内容,但是有的时候,我们不需要显示,那么就可以用这个方法来设置了。

    注意,必须在发送字符之前设置,设置之后在之后的代码中都一直有效。比如:

    process = pexpect.spawn('cat')
    
    # 默认情况下,下面的1234这个字符串会显示2次,一次是pexpect返回的,一次是cat命令返回的
    process.sendline("1234")
    
    # 现在我们关闭pexpect()的echo功能
    process.setecho(False)
    
    # 下面的字符只会显示一次了,这是由cat返回的
    process.sendline("abcd")
    
    # 现在重新开启echo功能,就可以再次看到我们发送的字符了
    process.setecho(True)
    

    setwinsize() - 控制台窗口大小

    如果子程序是一个控制台(TTY),比如 SSH 连接、 Telnet 连接这种通过网络登陆到系统并发送命令的都算控制台,那么可以用这个方法来设置这个控制太的大小(或者说长宽)。

    它的调用方式是 process.setwinsize(r, c)

    默认值是 setwinsize(24, 80),其中 24 是高度,单位是行; 80 是宽度,单位是字符。

    为什么要用它?想像下面的场景:

    有的时候你通过pexpect登陆到某个ssh控制台之后,又用 interact() 来将控制权交给用户,然后用户到控制台里面写自己的命令,如果命令比较长,就会发现当命令到屏幕边缘之后不会自动换行,而是又返回到这一行的最前面重新覆盖前面的字符;这不会影响命令的实际效果,但是很恼人。
    这种情况用 setwinsize() 就可以解决,找到自己终端支持的长度,重新设置一下,比如 setwinsize(25, 96 ),如果设置的正确的话就可以解决了。

    wait() - 执行等待

    直到被调用的子程序执行完毕之前,程序都停止(或者说等待)执行。它不会从被调用的子程序中读取任何内容。

    waitnoecho()

    它使用的地方比较特殊,唯一匹配的地方就是:当子程序的 echo 功能被设置为 Fals 时。

    看起来很奇怪?其实这个功能是基于一个很让人难以置信但的确是真实的情况:

    在命令行模式下,很多要求输入密码的地方,比如 FTP/SSH 等,密码实际上都会在你输入之后又重新返回并打印出来的,但是为什么我们看不到我们自己输入的密码呢?这就是因为密码在要打印出来之前被程序将 echo 功能设置为 False 了。

    现在知道为什么有这么一个方法了吧?比如要进行一个 ssh 连接时,如何检查是否要输入密码?用关键字 password 是一个方法,但还有一个方法就是这样:

    # 启动ssh连接
    process = pexpect.spawn("ssh user@example.com")
    
    # 等待echo被设置为False,这就意味着本地不会有回显
    process.waitnoecho()
    process.sendline('mypassword')
    

    可以设置超时时间,默认是:waitnoecho(timeout=-1),表示和系统设置的超时时间相同,也可以设置为 None 表示永远等待,直到回显被设置为 False ,当然还可以设置其他的数字来表示超时时间。

    write() - 发送字符串

    类似于send()命令,只不过不会返回发送的字符数。

    writelines() - 发送包含字符串的列表

    类似于 write() 命令,只不过接受的是一个字符串列表, writelines() 会向子程序一条一条的发送列表中的元素,但是不会自动在每个元素的最后加上回车换行符。

    与 write() 相似的是,这个方法也不会返回发送的字符数量。

    特殊变量

    pexpect.EOF - 匹配终止信号

    EOF 变量使用范围很广泛,比如检查 ssh/ftp/telnet 连接是否终止啊,文件是否已经到达末尾啊。 pexpect 大部分脚本的最后都会检查 EOF 变量来判断是不是正常终止和退出,比如下面的代码:

    process.expect("ftp>")
    process.sendline("by")
    process.expect(pexpect.EOF)
    print "ftp connect terminated."
    

    pexpect.TIMEOUT - 匹配超时信号

    TIMEOUT 变量用来匹配超时的情况,默认情况下 expect 的超时时间是 60 秒,如果超过 60 秒还没有发现期待的关键字,就会触发这个行为,比如:

    # 匹配pexpect.TIMEOUT的动作,只有超时事件发生的时候才会有效
    index = process.expect(['ftp>', pexpect.TIMEOUT],)
    if index == 1:
        process.interactive()   ; # 将控制权交给用户
    elif index == 2:
        print "Time is out."
        process.kill(0)         ; # 杀掉进程
    
    
    
    # 那么怎么改变超时时间呢?其实可以修改spawn对象里的timeout参数:
    # 下面的例子仅仅加了一行,这样就改变了超时的时间了
    process.timeout = 300   ; # 注意这一行
    index = process.expect(['ftp>', pexpect.TIMEOUT],)
    if index == 1:
        process.interactive()   ; # 将控制权交给用户
    elif index == 2:
        print "Time is out."
        process.kill(0)         ; # 杀掉进程
    

    process.before/after/match - 获取程序运行输出

    当 expect() 过程匹配到关键字(或者说正则表达式)之后,系统会自动给3个变量赋值,分别是 before, after 和 match

    • process.before - 保存了到匹配到关键字为止,缓存里面已有的所有数据。也就是说如果缓存里缓存了 100 个字符的时候终于匹配到了关键字,那么 before 就是除了匹配到的关键字之外的所有字符
    • process.after - 保存匹配到的关键字,比如你在 expect 里面使用了正则表达式,那么表达式匹配到的所有字符都在 after 里面
    • process.match - 保存的是匹配到的正则表达式的实例,和上面的 after 相比一个是匹配到的字符串,一个是匹配到的正则表达式实例

    如果 expect() 过程中发生错误,那么 before 保存到目前位置缓存里的所有数据, after 和 match 都是 None

    self.exitstatus | self.signalstatus

    上面的2个值用来保存spawn子程序的退出状态,但是注意:只有使用了 process.close() 命令之后这 2 个参数才会被设置。

    其他说明

    CR/LF约定

    众所周知的是:世界上有很多种回车换行约定,它们给我们造成了很多麻烦,比如:

    • windows 中用 \r\n 表示回车换行
    • Linux like 系统中用 \r 表示回车换行
    • Mac 系统中用 \n 表示回车换行

    这种种回车换行约定对代码移植造成了很大的困难,几乎所有全平台支持的程序语言都有它们自己的解决方案,而 pexpect 的解决方案就是:

    不管哪个平台,回车换行都替换成 \r\n

    所以,如果我们要在expect中匹配回车换行符号的话,就必须这么做:

    process.expect('\r\n')
    
    # 想匹配一行里的最后一个单词:
    process.expect('\w+\r\n')
    
    # 下面的匹配方式是错误的(在其他脚本语言中是正确的,比如TCL语言的Expect实现中,这也是很容易搞混淆的地方):
    process.expect('\r')
    

    $ * + 约定

    正则表达式中, $ 符号表示从一行中的最后开始匹配——但是在 pexpect 中是无效的。如果要匹配一行的最后,那么必须有一行数据存在,也就是有回车换行符,但是 pexpect 的处理不是按行来进行的,它一次仅仅读一个并且处理一个字符,而且不会处理【未来】的数据。

    所以不管什么时候,都不要在 expect() 中用 $ 符号来匹配。

    正因为pexpect一次仅仅处理一个字符,所以加号 (+) 、星号 (*) 的功能也无效了,比如:

    # 无论何时,都只会返回一个字符
    process.expect(".+")
    
    # 无论何时,都只会返回空字符
    process.expect(".*")
    

    程序调试

    如果要调试pexpect,那么可以使用下面的方式:

    str(processHandle)
    
    # 通过 pexpect.spawn() 可以创建一个进程,并通过操作这个进程的句柄来控制程序。
    # 但是如果将这个句柄用 str() 函数重载一下呢?它会显示这个控制句柄的一系列内部信息,比如:
    process = pexpect.spawn("ftp sw-tftp")
    print str(process)
    # <pexpect.spawn object at 0x2841cacc>
    version: 2.3 ($Revision: 399 $)
    command: /usr/bin/ftp
    args: ['/usr/bin/ftp', 'sw-tftp']
    searcher: searcher_re:
        0: EOF
    buffer (last 100 chars):
    before (last 100 chars): was 14494 bytes in 1 transfers.
    221-Thank you for using the FTP service on sw-tftp.
    221 Goodbye.
    
    after: <class 'pexpect.EOF'>
    match: <class 'pexpect.EOF'>
    match_index: 0
    exitstatus: 0
    flag_eof: True
    pid: 50733
    child_fd: 3
    closed: False
    timeout: 30
    delimiter: <class 'pexpect.EOF'>
    logfile: None
    logfile_read: None
    logfile_send: None
    maxread: 2000
    ignorecase: False
    searchwindowsize: None
    delaybeforesend: 0.05
    delayafterclose: 0.1
    delayafterterminate: 0.1
    

    技巧和陷阱

    循环匹配

    Python 的 pexpect 模块与 TCL 的 expect 相比有些功能明显支持不足,其中就包括循环匹配。 TCL 的 expect 模块可以给出一系列匹配关键字,然后通过 continue 语句的设置保证同一个 expect 可以在关键字列表中重新循环。

    比如一个 expect 有 3 个关键字,其中匹配到第二个关键字的时候会碰见 continue 语句,那么下一次匹配就重复这个 expect 过程,这是一个很有用的功能,比如超时时间设置为 10 秒,然后重复 3 次才会真正超时的情况。

    可惜的是 Python 的 pexpect 没有这样的功能。但是想模拟这种情况也不是不可以,可以通过 while 语句来完成,比如:

    while True:
        index = process.expect([
            pexpect.TIMEOUT,
            pexpect.EOF,
        ]}
        if index == 0:
            print "time is out"
            # 重新从开始匹配
            continue
    elif index == 1:
        print "Terminate."
        # 终止循环
        break
    

    获取 before 中内容的战略与清空 buffer

    绝大多数情况下我们都会利用before变量来获取命令执行的结果。但是,你真的知道怎么用好 before 么?

    before 中到底什么时候保存你所需的内容?这个细节必须非常清楚,我们以一个调用一个命令为例子:

    这里我们预计是在 linux 系统中,下面的 handle 是一个 spawn 后的句柄,而 prompt 则是 bash 的提示符。我们预计做这样的步骤:

    1. 匹配提示符,以此判断系统已经准备好接受命令
    2. 发送命令
    3. 获取命令执行后的结果
    handle.expect(prompt)
    handle.sendline("ls –l")
    handle.expect(prompt)
    output = handle.before
    

    一共 4 个语句,就可以获取 ls –l 命令的结果了,但是且慢,是否发现有什么不合理的地方?

    第一句和第二句分别是匹配系统提示符和发送命令,这都是比较正常的。

    但是为什么第三句是再次匹配系统提示符?在一般的想像下,发送命令之后,设备就会执行并返回结果了,那么完全就可以用 handle.before 语句来获取到这些内容了才对啊?

    实际上,从 before 这个单词就可以大概明白,它并不是实时生效的,它里面的内容,实际上是上一次 expect 匹配之后,除掉匹配到的关键字本身,系统缓存中剩余下来的全部内容。也就是说,如果第三句就是 output = handle.before的话,那么它里面的内容就是第一句的那个 expect 中去掉 prompt 内容后缓存中剩下来的内容。显然,这里面不会包括后面 ls –l 命令的内容了。

    那么想获取 ls –l 的内容,唯一的办法是再增加一个 expect 关键字匹配。这是非常关键的一点。

    另外, pexpect 中的 buffer 是一个关键,但又不能被直接操作的变量,它保存的是运行过程中每一个 expect 之后的所有内容,随时被更新。而 before/after 都是直接源于它的,而 expect 的关键字匹配本身也是在 buffer 中做匹配的。

    正因为它的重要性,对这个变量中的内容需要特别的警惕。比如我们将登陆设备,发送命令,退出设备这3个步骤写进3个函数的时候,最好保证每个步骤都不会影响下一个步骤,在每个步骤开始的时候,最好做这样的操作:

    handle.buffer = ""
    

    代码实例

    FTP服务器的登陆

    下面的代码比较简单,就是登陆到一个 FTP 服务器,并自动输入密码,等进入服务器以后,先输入几个预定义的命令,然后将控制权交还给用户,用户操作完成后按 <kbd>ctrl+]</kbd> 表示自己操作完成了,脚本再自动退出 ftp 登陆。

    #!/usr/bin/env python
    
    import sys
    import pexpect
    
    # FTP服务器的标准提示符
    ftpPrompt = 'ftp>'
    
    # 启动FTP服务器,并将运行期间的输出都放到标准输出中
    process = pexpect.spawn('ftp sw-tftp')
    process.logfile_read = sys.stdout
    
    # 服务器登陆过程
    process.expect('[Nn]ame')
    process.sendline('dev')
    process.expect('[Pp]assword')
    process.sendline('abcd1234')
    
    # 先自动输入一些预定命令
    cmdList = ("passive", 'hash')
    
    for cmd in cmdList:
        process.expect(ftpPrompt)
        process.sendline(cmd)
    
    process.expect(ftpPrompt)
    
    # 在这里将FTP控制权交还给用户,用户输入完成后按 ctrl+] 再将控制权还给脚本
    # ctrl+] 交还控制权给脚本是默认值,用户还可以设置其他的值,比如 ‘\x2a’
    # 就是用户按星号的时候交还。这个值实际上是 ASCII 的16进制码,它们的对应关系
    # 可以自己去其他地方找一下,但是注意必须是16进制的,并且前缀是 \x
    process.interact()
    
    # 当用户将控制权交还给脚本后,再由脚本退出ftp服务器
    # 注意下面这个空的sendline()命令,它很重要。用户将控制权交还给脚本的时候,
    # 脚本缓存里面是没任何内容的,所以也不可能匹配,这里发送一个回车符会从服务器取得
    # 一些内容,这样就可以匹配了。
    # 最后的EOF是确认FTP连接完成的方法。
    process.sendline()
    process.expect(ftpPrompt)
    process.sendline('by')
    process.expect(pexpect.EOF)
    

    上面的脚本实际上缺少很多错误处理,比如登陆以后用户名或者密码错误,或者无法连接服务器之类的,但是核心动作已经完整了。



    展开全文
  • Python的Pexpect模块详解

    万次阅读 2017-06-23 23:35:11
    对于存在交互过程的远程访问,如ssh, ftp, mencoder, passwd等,通过Pexpect模块可以根据应用的输出控制交互过程,从而提高容错性。 Pexpect模块首先通过生成子应用以代理交互应用,这样就可以通过检测子应用的模式...

    对于存在交互过程的远程访问,如ssh, ftp, mencoder, passwd等,通过Pexpect模块可以根据应用的输出控制交互过程,从而提高容错性。
    Pexpect模块首先通过生成子应用以代理交互应用,这样就可以通过检测子应用的模式匹配情况以响应交互应用的输出。

    作为Don Libes的Expect实现之一,Pexpect模块是一个纯Python实现。

    Python也有其他的类Expect模块,但是这些模块往往依赖于TCL和Expect扩展模块,或编译时依赖于C扩展模块。而Pexpect模块除了基于Python标准库中的pty模块之外,完全独立。从Pexpect 4.0开始,Pexpect模块可运行于Windows系统和POSIX系统。当然,由于pexpect.spawn()和pexpect.run()依赖于Python标准库中的pty模块,而pty模块只在POSIX系统中存在,所以Windows系统上的功能有限。

    1. Pexpect模块的安装:
    Python 3.3或Python 2.7以上
    pip install pexpect
    2. Pexpect模块的组成:

    1) pexpect.run()函数

    该函数执行一个命令并返回命令的结果,可用以替代os.system()。

    pexpect.run('ls -la')


    2) pexpect.SpawnBase类

    抽象基类,永远不能直接实例化。其中定义的主要属性和方法如下:

    • self.before = None
    • self.after = None
    • def expect(self, pattern, timeout=-1, searchwindowsize=-1, async_=False, **kw)

    3) pexpect.spawn类

    继承自SpawnBase类。用法如下:

    child = pexpect.spawn('/usr/bin/ftp')
    child = pexpect.spawn('/usr/bin/ssh user@example.com')
    child = pexpect.spawn('ls -latr /tmp')
    child = pexpect.spawn('/usr/bin/ftp', [])
    child = pexpect.spawn('/usr/bin/ssh', ['user@example.com'])
    child = pexpect.spawn('ls', ['-latr', '/tmp'])
    仔细观察上述语句,给出了两种创建子应用的方式。

    再如:

    child = pexpect.spawn('/bin/bash -c "ls -l | grep LOG > logs.txt"')
    child.expect(pexpect.EOF)
    等价于
    child = pexpect.spawn('/bin/bash', ['-c', 'ls -l | grep LOG > logs.txt'])
    child.expect(pexpect.EOF)

    • expect()方法

    下面就可以对子应用调用方法,检测交互过程的输出并进行相应的输入。

    import pexpect
    ssh_client = pexpect.spawn("ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2211 user@host")
    ssh_client.expect(...)
    expect()方法是最常用的方法之一,等待子应用返回指定的字符串。expect()方法的特性如下:

      • Pexpect一次从子应用中读取一个字符,所以在字符模式中,$符号不能匹配为行末或字符串结尾。
      • 要匹配行末使用'\r\n',这适合Windows系统和POSIX系统。
      • expect()返回被匹配的字符模式的序号,从0开始
      • 最少匹配原则
    ssh_client.expect ('.+')#只匹配一个.
    ssh_client.expect ('.*')#什么都不匹配
      • 如果没有任何字符模式被匹配,将抛出超时异常,默认超时时间为30s
    ssh_client.expect (['Permission denied', 'Terminal type', '[#\$] '], timeout=60)#超时时间60s
    ssh_client.expect (['Permission denied', 'Terminal type', '[#\$] '], timeout=None)#永不超时
    • 子应用在每次expect()调用的前后,子应用输出的文本分别写入到before和after属性
    ssh_client.before属性,包含子应用输出的文本,直到出现了期望的字符串
    ssh_client.after属性,包含匹配了的字符串

    • send()

    写入一个字符串到子应用

    • sendline()
    写入一行到子应用
    • logfile属性

    ssh_client.logfile = sys.stdout#将日志输出到控制台

    3) pexpect.EOF类
    默认遇到子应用的EOF,expect()会抛出异常
    4) pexpect.TIMEOUT类

    index = p.expect(['good', 'bad', pexpect.EOF, pexpect.TIMEOUT])
    if index == 0:
        do_something()
    elif index == 1:
        do_something_else()
    elif index == 2:
        do_some_other_thing()
    elif index == 3:
        do_something_completely_different()

    参考链接:

    https://pypi.python.org/pypi/pexpect/
    https://pexpect.readthedocs.io/en/stable/
    https://pexpect.readthedocs.io/en/stable/api/index.html
    https://github.com/pexpect/pexpect


    展开全文
  • Pexpect模块的安装

    2016-04-07 14:05:00
    Pexpect模块的安装 下载地址:https://pypi.python.org/pypi/pexpect/ 解压后在目录下运行:python ./setup.py install (必须是root权限,运行前检查文件权限,必须是root权限才能正确安装,否则安装失败) ...
  • Python 安装pexpect模块

    2016-09-19 17:58:32
    安装Python下载pexpect模块:https://pypi.python.org/pypi/pexpect/#downloads解压后在目录下运行:python ./setup.py install (必须是root权限)如果没有使用root权限,你只需要把lib的路径放入sys.path,这样便...
  • pexpect模块pxssh类源代码 SSH登录指定的主机。 def login (self, server, username=None, password='', terminal_type='ansi', original_prompt=r"[#$]", login_timeout=10, port=None, ...
  • Python入门之——pexpect模块

    千次阅读 2021-01-04 13:08:43
    pexpect可以理解为Linux下的expect的Python封装、通过pexpect可以实现对ssh、ftp、passwd、telnet等命令行进行自动交互,而无需人工干涉来达到自动化的目的。比如我们可以模拟一个FTP登录时所有交互,包括输入主机...
  • Python中的Pexpect模块的简单使用

    千次阅读 2018-11-01 22:54:30
    Pexpect 是一个用来启动子程序并对其进行自动控制的 Python 模块Pexpect 可以用来和像 ssh、ftp、passwd、telnet 等命令行程序进行自动交互。以下所有代码都是在Kali Linux环境下,python 2.7.13 Pexpect中的 ...
  • pexpect是一个纯pyth实现的模块pexpect可以某些交互式子进程进行交互从而代替手工操作。比如使用passwd命令需要人工输入密码,如果使用pexpect可以通过sendline自动化进行。 几个关键词掌握了就可以使用了。 spawn...
  • 说明 当我们需要用脚本实现,远程登录或者远程操作的时候,都要去解决如何自动输入密码的问题,一般来说有3种实现...下面介绍的代码,是使用python的pexpect模块实现的: 代码 import os import sys import pe
  • [root@localhost ~]# cat ex_ssh.py#!/usr/local/python3/bin/python3import pexpectdef exec_command(user,host,password): new_connection = 'Are you sure you want to continue connecting' conn = ...
  • pexpect模块的使用

    2019-01-29 15:06:52
    Pexpect 是 Expect 语言的一个 Python 实现,是一个用来启动子程序,并使用正则表达式对程序输出做出特定响应,以此实现与其自动交互的 Python 模块Pexpect 的使用范围很广,可以用来实现与 ssh、ftp 、telnet 等...
  • python pexpect模块详解附常用脚本

    千次阅读 2013-11-11 11:03:14
    1.下载 wget https://pypi.python.org/packages/source/p/pexpect/pexpect-2.4.tar.gz#md5=fe82d69be19ec96d3a6650af947d5665
  • 通过pexpect获取集群主机信息import pexpectip = 'xx'cmd = 'xx'ssh = pexpect.spawn('ssh %s %s' %(ip,cmd))r = ssh.read()print r 转载于:https://blog.51cto.com/11888798/1932857...
  • /usr/bin/env pythonimport pexpect import sys ip=sys.argv[1]dbname=sys.argv[2]dbhost= sys.argv[3:]child = pexpect.spawn ( ‘ssh -p 10022 -o “StrictHostKeyChecking no” uss@%s@%s’ %(ip)) #取消首次...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,896
精华内容 758
关键字:

pexpect模块