pexpect常用API笔记
spawn()
spawn
用来执行一个程序,它返回这个程序的操作句柄,以后可以通过操作这个句柄来对这个程序进行操作。
参数以及默认值如下:
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)
其中比较常用的参数:
- command: 开启子终端的命令 必需
- timeout: 等待超时的时间 默认值:30秒
- logfile: 日志输出设备 默认值:无
- echo: 设置是否显示正在输入的指令 默认值:true
- encoding: 输出的编码 默认值:无
示例:
minicom_cmd = 'sudo minicom -D /dev/USB -b 115200'
child = pexpect.spawn(minicom_cmd, timeout=30, echo=False, encoding = 'utf-8')
logfile
logfile
可以控制子终端输出的设备,可以设置其输出到标准输出sys.stdout
或者log文件中。
示例:
child.logfile = sys.stdout # 将所有日志输出到 sys.stdout
child.logfile_read = sys.stdout # 将子终端返回的日志输出到 sys.stdout
child.logfile_send = sys.stdout # 将pexpect发送的日志输出到 sys.stdout
minicom_log = open('mini_log.txt','ab+')
child.logfile_read = minicom_log # 将子终端返回的日志输出到 minicom_log文件
需要注意的是:输出设备是对输出形式以及编码是非常敏感的,
如果没有使用正确的设置,运行就会报错。
# 如果没有指定输出编码,默认就是二进制输出
child = pexpect.spawn(minicom_cmd, timeout=30, echo=False)
# 指定输出设备为文件时,就要以二进制方式打开
minicom_log = open('mini_log.txt','ab+')
child.logfile = minicom_log
# encoding = 'utf-8' 指定了输出编码为'utf-8'
child = pexpect.spawn(minicom_cmd, timeout=30, echo=False, encoding = 'utf-8')
# 指定输出设备为文件时,就要以正常方式打开
minicom_log = open('mini_log.txt','a+')
child.logfile = minicom_log
指定输出设备为标准输出,也就是输出到当前的窗口,编码就要改成'utf-8',
否则就会报出错误:TypeError: write() argument must be str, not bytes
child = pexpect.spawn(minicom_cmd, timeout=30, echo=False, encoding = 'utf-8')
child.logfile = sys.stdout
expect()
当 spawn() 启动了一个程序并返回程序控制句柄后,就可以用 expect() 方法来等待指定的关键字了。它最后会返回 0 表示匹配到了所需的关键字,如果后面的匹配关键字是一个列表的话,就会返回一个数字表示匹配到了列表中第几个关键字,从 0 开始计算。
child.expect('[Nn]ame')
child.expect('[Nn]ame', timeout=-1)
- 上面的代码表示:匹配 child 这个句柄中的 name 关键字,其中 n 不分大小写。
- 上面的关键字一旦匹配,就会返回0表示匹配成功,但是如果一直匹配不到呢?默认是会一直等下去,但是如果设置了 timeout 的话就会超时。
- timeout 不设置或者设置为-1的话,超时时间就采用self.timeout的值,默认是30秒。
- 所以要注意匹配的东西,如果不准确填写匹配符,执行expect次数多的话,会造成程序运行缓慢。
expect_exact() - 精确匹配
它的使用和 expect() 是一样的,唯一不同的就是它的匹配列表中不再使用正则表达式。
从性能上来说 expect_exact() 要更好一些,因为即使你没有使用正则表达式而只是简单的用了几个字符 expect() 也会先将它们转换成正则表达式模式然后再搜索,但 expect_exact() 不会,而且也不会把一些特殊符号转换掉。
expect_list() - 预转换匹配
使用方式和 expect() 一样,唯一不同的就是它里面接受的正则表达式列表只会转换一次。
expect() 稍微有点笨,每调用一次它都会将内部的正则表达式转换一次(当然也有其他办法避免),如果你是在以后循环中调用 expect() 的话,多余的转换动作就会降低性能,在这种情况下建议用 expect_list() 来代替。
cpl = self.compile_pattern_list(my_pattern)
while 1:
child.expect_list(cpl, timeout=-1, searchwindowsize=-1)
send()
send() 用来向程序发送指定的字符串,它的使用没什么特殊的地方,比如:
child.expect("ftp>")
child.send("by\n")
这个方法会返回发送字符的数量。
sendline() - 发送带回车符的字符串
sendline() 和 send() 唯一的区别就是在发送的字符串后面加上了回车换行符,这也使它们用在了不同的地方:
只需要发送字符就可以的话用send()
如果发送字符后还要回车的话,就用 sendline()
它也会返回发送的字符数量
sendcontrol() - 发送控制信号
sendcontrol() 向子程序发送控制字符,比如 ctrl+C 或者 ctrl+D 等
child.sendcontrol('C') # ctrl+C
sendeof() - 发送 EOF 信号
向子程序发送 End Of File 信号。
sendintr() - 发送终止信号
向子程序发送 SIGINT 信号,相当于 Linux 中的 kill 2 ,它会直接终止掉子进程。
interact()
interact() 表示将控制权限交给用户(或者说标准输入)。
需要注意的是,通常在使用命令行终端时,用户可以看到自己的输入,也就是终端会回显出用户输入的字符
但是如果下面的代码将 echo=False ,则interact()移交控制权给客户时,终端就不会回显输入的字符
child = pexpect.spawn(minicom_cmd, timeout=30, echo=False, encoding = 'utf-8')
child.interact()
child.interact(escape_character='\x1d', input_filter=None, output_filter= None)
通过设置 escape_character 的值,可以定义返回码,默认是 ctrl+] 或者说 ^],当输入了返回码以后,
脚本会将控制权从用户那里重新拿回来,然后继续向下执行。
ctrl+] 交还控制权给脚本是默认值,用户还可以设置其他的值,
比如 \x2a就是用户按星号的时候交还,这个值实际上是 ASCII 的16进制码,
它们的对应关系可以自己去其他地方找一下,但是注意必须是16进制的,并且前缀是 \x
close()
close() - 停止应用程序
如果想中途关闭子程序,那么可以用 close 来完成,调用这个方法后会返回这个程序的返回值。
如果设置 force=True 会强行关闭这个程序,大概的过程就是先发送 SIGHUP 和 SIGINT 信号,如果都无效的话就发 SIGKILL 信号,反正不管怎么样都会保证这个程序被关闭掉。
child.close(force=True)
terminate() - 停止应用程序
可以看作是上面 close() 的别名,不管是功能还是使用方法都和close()一样。
Kill() - 发送 SIGKILL 信号
向子程序发送 SIGKILL 的信号。
参考
官网
https://pypi.org/project/pexpect/
pexpect官方文档
https://pexpect.readthedocs.io/en/stable/install.html