探索 Pexpect,第 1 部分:剖析 Pexpect

概述

Pexpect 是 Don Libes 的 Expect 语言的一个 Python 实现,是一个用来启动子程序,并使用正则表达式对程序输出做出特定响应,以此实现与其自动交互的 Python 模块。 Pexpect 的使用范围很广,可以用来实现与 ssh、ftp 、telnet 等程序的自动交互;可以用来自动复制软件安装包并在不同机器自动安装;还可以用来实现软件测试中与命令行交互的自动化。

下载

Pexpect 可以从 SourceForge 网站下载。 本文介绍的示例使用的是 2.3 版本,如不说明测试环境,默认运行操作系统为 fedora 9 并使用 Python 2.5 。

安装

依赖

Python 版本 2.4 或者 2.5

pty module ,pty 是任何 Posix 系统标准库的一部分

由于其依赖 pty module ,所以 Pexpect 还不能在 Windows 的标准 python 环境中执行,如果想在 Windows 平台使用,可以使用在 Windows 中运行 Cygwin 做为替代方案。

遵循 MIT 许可证

根据 Wiki 对 MIT License 的介绍“该模块被授权人有权利使用、复制、修改、合并、出版发行、散布、再授权及贩售软件及软件的副本。被授权人可根据程序的需要修改授权条款为适当的内容。在软件和软件的所有副本中都必须包含版权声明和许可声明。”

Pexpect 提供的 run() 函数:

清单 1. run() 的定义

函数 run 可以用来运行命令,其作用与 Python os 模块中 system() 函数相似。run() 是通过 Pexpect类实现的。

如果命令的路径没有完全给出,则 run 会使用 which 命令尝试搜索命令的路径 。

清单 2. 使用 run()执行 svn 命令

与 os.system() 不同的是,使用 run() 可以方便地同时获得命令的输出结果与命令的退出状态 。

清单 3. run() 的返回值

command_out 中保存的就是 /bin 目录下的内容。

Pexpect 提供的 spawn() 类:

使用 Pexpect 启动子程序

清单 4. spawn 的构造函数

spawn是Pexpect模块主要的类,用以实现启动子程序,它有丰富的方法与子程序交互从而实现用户对子程序的控制。它主要使用 pty.fork() 生成子进程,并调用 exec() 系列函数执行 command 参数的内容。

可以这样使用:

清单 5. spawn() 使用示例

当子程序需要参数时,还可以使用一个参数的列表:

清单 6. 参数列表示例

在构造函数中,maxread 属性指定了 Pexpect 对象试图从 tty 一次读取的最大字节数,它的默认值是2000字节 。

由于需要实现不断匹配子程序输出, searchwindowsize 指定了从输入缓冲区中进行模式匹配的位置,默认从开始匹配。

logfile 参数指定了 Pexpect 产生的日志的记录位置。

例如:

清单 7. 记录日志

还可以将日志指向标准输出:

清单 8. 将日志指向标准输出

如果不需要记录向子程序输入的日志,只记录子程序的输出,可以使用:

清单 9. 记录输出日志

使用 Pexpect 控制子程序

为了控制子程序,等待子程序产生特定输出,做出特定的响应,可以使用 expect 方法。

清单 10. expect() 定义

在参数中: pattern 可以是正则表达式, pexpect.EOF , pexpect.TIMEOUT ,或者由这些元素组成的列表。需要注意的是,当 pattern 的类型是一个列表时,且子程序输出结果中不止一个被匹配成功,则匹配返回的结果是缓冲区中最先出现的那个元素,或者是列表中最左边的元素。使用 timeout 可以指定等待结果的超时时间 ,该时间以秒为单位。当超过预订时间时, expect 匹配到pexpect.TIMEOUT。

如果难以估算程序运行的时间,可以使用循环使其多次等待直至等待运行结束:

清单 11. 使用循环

expect() 在执行中可能会抛出两种类型的异常分别是 EOF and TIMEOUF,其中 EOF 通常代表子程序的退出, TIMEOUT 代表在等待目标正则表达式中出现了超时。

清单 12. 使用并捕获异常

此时可以将这两种异常放入expect等待的目标列表中:

清单 13. 避免异常

expect 不断从读入缓冲区中匹配目标正则表达式,当匹配结束时 pexpect 的 before 成员中保存了缓冲区中匹配成功处之前的内容, pexpect 的 after 成员保存的是缓冲区中与目标正则表达式相匹配的内容。

清单 14. 打印 before 成员的内容

此时 child.before 保存的就是在根目录下执行 ls 命令的结果。

清单 15. send 系列函数

这些方法用来向子程序发送命令,模拟输入命令的行为。 与 send() 不同的是 sendline() 会额外输入一个回车符 ,更加适合用来模拟对子程序进行输入命令的操作。 当需要模拟发送 “Ctrl+c” 的行为时,还可以使用 sendcontrol() 发送控制字符。

清单 16. 发送 ctrl+c

由于 send() 系列函数向子程序发送的命令会在终端显示,所以也会在子程序的输入缓冲区中出现,因此不建议使用 expect 匹配最近一次 sendline() 中包含的字符。否则可能会在造成不希望的匹配结果。

清单 17. interact() 定义

Pexpect还可以调用interact() 让出控制权,用户可以继续当前的会话控制子程序。用户可以敲入特定的退出字符跳出,其默认值为“^]” 。

下面展示一个使用Pexpect和ftp交互的实例。

清单 18. ftp 交互的实例:

该程序与 ftp 做交互,登录到 ftp.openbsd.org ,当提述输入登录名称和密码时输入默认用户名和密码,当出现 “ftp>” 这一提示符时切换到 pub/OpenBSD 目录并下载 README 这一文件。

以下实例是上述方法的综合应用,用来建立一个到远程服务器的 telnet 连接,并返回保存该连接的 pexpect 对象。

清单 19. 登录函数:

Pxssh 类的使用:

Pxssh 做为 pexpect 的派生类可以用来建立一个 ssh 连接,它相比其基类增加了如下方法:

login() 建立到目标机器的ssh连接 ;

losuckgout() 释放该连接 ;

prompt() 等待提示符,通常用于等待命令执行结束。

下面的示例连接到一个远程服务器,执行命令并打印命令执行结果。

该程序首先接受用户输入用户名和密码,login 函数返回一个 pxssh 对象的链接,然后调用 sendline() 分别输入 “uptime”、“ls” 等命令并打印命令输出结果。

清单 20. pxssh 示例

Pexpect 使用中需要注意的问题:

spawn() 参数的限制

在使用spawn执行命令时应该注意,Pexpect 并不与 shell 的元字符例如重定向符号 > 、>> 、管道 | ,还有通配符 * 等做交互,所以当想运行一个带有管道的命令时必须另外启动一个 shell ,为了使代码清晰,以下示例使用了参数列表例如:

清单 21. 启动新的 shell 执行命令

与线程共同工作

Perl 也有 expect 的模块 Expect-1.21,但是 perl 的该模块在某些操作系统例如 fedora 9 或者 AIX 5 中不支持在线程中启动程序执行以下实例试图利用多线同时程登录到两台机器进行操作,不使用线程直接调用时 sub1() 函数可以正常工作,但是使用线程时在 fedora9 和 AIX 5 中都不能正常运行。

清单 22. perl 使用 expect 由于线程和 expect 共同使用导致不能正常工作的程序

Pexpect 则没有这样的问题,可以使用多线程并在线程中启动程序运行。但是在某些操作系统如 fedora9 中不可以在线程之间传递 Pexpect 对象。

清单 使用 Pexpect 在线程中启动控制子程序

应用实例:

在实际系统管理员的任务中,有时需要同时管理多台机器,这个示例程序被用来自动编译并安装新的内核版本,并重启。它使用多线程,每个线程都建立一个到远程机器的 telnet 连接并执行相关命令。 该示例会使用上文中的登录函数。

清单 23. 管理多台机器示例

相关主题

访问 Expect 的主页,了解更多 Expect 的内容。

参考 Wiki 上关于 MIT 许可证的介绍。

查看文章“ Expect 在网络管理中发挥着重要作用”介绍 Expect 在网络管理中的应用。

Perl 语言中的 Expect 了解 Perl 语言中的 Expect 。

在 developerWorks 上查阅所有 Linux 技巧和 Linux 教程。

探索 Pexpect,第 2 部分:Pexpect 的实例分析

概述

通过本系列第一部分《探索 Pexpect,第 1 部分:剖析 Pexpect 》(请参阅参考资料)的介绍,相信大家已经对 Pexpect 的用法已经有了比较全面的了解,知道 Pexpect 是个纯 Python 语言实现的模块,使用其可以轻松方便的实现与 ssh、ftp、passwd 和 telnet 等程序的自动交互,但是读者的理解还可能只是停留在理论基础上,本文将从实际例子入手具体介绍 Pexpect 的使用场景和使用心得体验,实例中的代码读者都可以直接拿来使用,相信会对大家产生比较大的帮助。 以下是本文所要介绍的所有 Pexpect 例子标题:

例 1:ftp 的使用(注:spawn、expect 和 sendline 的使用)

例 2:记录 log(注:logfile、logfile_send和logfile_read的使用)

例 3:ssh 的使用

例 4:pxssh 的使用

例 5:telnet 的使用(注:interact 的使用)

pexpect 使用 tips

调试 pexpect 程序的 tips

pexpect 不会解释 shell 中的元字符

EOF 异常和 TIMEOUT 异常

使用 run() 来替代某些的 spawn 的使用

expect_exact() 的使用

expect() 中正则表达式的使用 tips

isalive() 的使用 tips

delaybeforesend 的使用 tips

例 1:ftp 的使用

本例实现了如下功能:ftp 登录到 develperWorks.ibm.com 主机上,并用二进制传输模式下载一个名叫 rmall的文件。

清单 1. ftp 的例子代码

注:

运行后,输出结果为:

本例 expect 函数中的 pattern 使用了 List,并包含了 pexpect.EOF和pexpect.TIMEOUT,这样出现了超时或者 EOF,不会抛出 expection 。(关于 expect() 函数的具体使用,请参阅参考资料)

如果程序运行中间出现了错误,如用户名密码错误,超时或者 EOF,远程 server 连接不上,都会使用 c hild.close(force=True) 关掉 ftp 子程序。调用 close 可以用来关闭与子程序的 connection 连接,如果你不仅想关闭与子程序的连接,还想确保子程序是真的被 terminate 终止了,设置参数 force=True,其最终会调用 c hild.kill(signal.SIGKILL) 来杀掉子程序。

例 2:记录 log

本例实现了如下功能:运行一个命令,并将该命令的运行输出结果记录到 log 文件中 ./command.py [-a] [-c command] {logfilename} -c 后接的是要运行的命令的名字,默认是“ls -l”; logfilename 是记录命令运行结果的 log 文件名,默认是“command.log”;指定 -a 表示命令的输出结果会附加在 logfilename 后,如果 logfilename 之前已经存在的话。

清单 2. 记录 log 的例子代码

注:

运行:./command.py -a -c who cmd.log

logfile:

只能通过 spawn 类的构造函数指定。在 spawn 类的构造函数通过参数指定 logfile 时,表示开启或关闭 logging 。所有的子程序的 input 和 output 都会被 copy 到指定的 logfile 中。设置 logfile 为 None 表示停止 logging,默认就是停止 logging 。设置 logfile 为 sys.stdout,会将所有东西 echo 到标准输出。

logfile_read和logfile_send:

logfile_read:只用来记录 python 主程序接收到 child 子程序的输出,有的时候你不想看到写给 child 的所有东西,只希望看到 child 发回来的东西。 logfile_send:只用来记录 python 主程序发送给 child 子程序的输入 logfile、logfile_read 和 logfile_send 何时被写入呢? logfile、logfile_read 和 logfile_send 会在每次写 write 和 send 操作后被 flush 。

调用 send 后,才会往 logfile 和 logfile_send 中写入,sendline/sendcontrol/sendoff/write/writeline 最终都会调用 send,所以 sendline 后 logfile 中一定有内容了,只要此时 logfile 没有被 close 。

调用 read_nonblocking 后,才会往 logfile 和 logfile_read 中写入,expect_loop 会调用 read_nonblocking,而 expect_exact 和 expect_list 都会调用 expect_loop,expect 会调用 expect_list,所以 expect 后 logfile 中一定有内容了,只要此时 logfile 没有被 close 。

如果调用的函数最终都没有调用 send 或 read_nonblocking,那么 logfile 虽然被分配指定了一个 file,但其最终结果是:内容为空。见下例:

清单 3. log 内容为空的例子代码

运行该脚本后,你会发现其实 log.txt 是空的,没有记录 ls -l 命令的内容,原因是没有调用 send 或 read_nonblocking,真正的内容没有被 flush 到 log 中。如果在 fout.close() 之前加上 p.expect(pexpect.EOF),log.txt 才会有 ls -l 命令的内容。

例 3:ssh 的使用

本例实现了如下功能:ssh 登录到某个用户指定的主机上,运行某个用户指定的命令,并输出该命令的结果。

清单 4. ssh 的例子代码

注:

运行后,输出结果为:

使用了 getpass.getpass() 来获得用户输入的密码,与 raw_input 不同的是,getpass.getpass() 不会将用户输入的密码字符串 echo 回显到 stdout 上。(更多 python 相关技术,请参阅参考资料)

例 4:pxssh 的使用

本例实现了如下功能:使用 pexpect 自带的 pxssh 模块实现 ssh 登录到某个用户指定的主机上,运行命令’ uptime ’和’ ls -l ’,并输出该命令的结果。

清单 5. 使用 pxssh 的例子代码

运行后,输出结果为:

pxssh 是 pexpect 中 spawn 类的子类,增加了 login, logout 和 prompt 几个方法,使用其可以轻松实现 ssh 连接,而不用自己调用相对复杂的 pexpect 的方法来实现。 pxssh 做了很多 tricky 的东西来处理 ssh login 过程中所可能遇到的各种情况。比如:如果这个 session 是第一次 login,pxssh 会自动接受远程整数 remote certificate ;如果你已经设置了公钥认证,pxssh 将不会再等待 password 的提示符。(更多 ssh 相关知识,请参阅参考资料) pxssh 使用 shell 的提示符来同步远程主机的输出,为了使程序更加稳定,pxssh 还可以设置 prompt 为更加唯一的字符串,而不仅仅是“ $ ”和“ # ”。

login 方法

使用原始 original_prompt 来找到 login 后的提示符(这里默认 original_prompt 是“$”或“#”,但是有时候可能也是别的 prompt,这时就需要在 login 时手动指定这个特殊的 prompt,见上例,有可能是“ > ”),如果找到了,立马使用更容易匹配的字符串来重置该原始提示符(这是由 pxssh 自己自动做的,通过命令 "PS1='[PEXPECT]\$ '" 重置原始提示符,然后每次 expect 匹配 \[PEXPECT\][\$\#])。原始提示符是很容易被混淆和胡弄的,为了阻止错误匹配,最好根据特定的系统,指定更加精确的原始提示符,例如 "Message Of The Day" 。 有些情况是不允许重置原始提示符的,这时就要设置 auto_prompt_reset 为 False 。而且此时需要手动设置 PROMPT 域为某个正则表达式来 match 接下来要出现的新提示符,因为 prompt() 函数默认是 expect 被重置过的 PROMPT 的。

prompt方法

匹配新提示符(不是 original_prompt)。注:这只是匹配提示符,不能匹配别的 string,如果要匹配特殊 string,需直接使用父类 spawn 的 expect 方法。 prompt 方法相当于是 expect 方法的一个快捷方法。如果auto_prompt_reset 为 False,这时需要手动设置 PROMPT 域为某个正则表达式来 match 接下来要出现的 prompt,因为 prompt() 函数默认是 expect 被重置过的 PROMPT 的。

logout方法

发送'exit'给远程 ssh 主机,如果有 stopped jobs,会发送'exit'两次。

例 5:telnet 的使用

本例实现了如下功能:telnet 登录到某远程主机上,输入命令“ls -l”后,将子程序的执行权交还给用户,用户可以与生成的 telnet 子程序进行交互。

清单 6. telnet 的例子代码

运行后,输出结果为:

interact方法

通常一个 python 主程序通过 pexpect.spawn 启动一个子程序,一旦该子程序启动后,python 主程序就可以通过 child.expect 和 child.send/child.sendline 来和子程序通话,python 主程序运行结束后,子程序也就死了。比如 python 主程序通过 pexpect.spawn 启动了一个 telnet 子程序,在进行完一系列的 telnet 上的命令操作后,python 主程序运行结束了,那么该 telnet session(telnet 子程序)也会自动退出。但是如果调用 child.interact,那么该子程序(python 主程序通过 pexpect.spawn 衍生成的)就可以在运行到 child.interact 时,将子程序的控制权交给了终端用户(the human at the keyboard),用户可以通过键盘的输入来和子程序进行命令交互,管理子程序的生杀大权,用户的键盘输入 stdin 会被传给子程序,而且子程序的 stdout 和 stderr 输出也会被打印出来到终端。 默认 ctrl + ] 退出 interact() 模式,把子程序的执行权重新交给 python 主程序。参数 escape_character 指定了交互模式的退出字符,例如 child.interact(chr(26)) 接下来就会变成 ctrl + z 退出 interact() 模式。

pexpect 使用 tips

调试 pexpect 程序的 tips

获得 pexpect.spawn 对象的字符串 value值,将会给 debug 提供很多有用信息。

清单 7. 打印 pexpect.spawn 对象的字符串 value 值的例子代码

将子程序的 input 和 output 打 log 到文件中或者直接打 log 到屏幕上也非常有用

清单 8. 记录 log 的例子代码

pexpect 不会解释 shell 中的元字符

pexpect 不会解释 shell 的元字符,如重定向 redirect,管道 pipe,和通配符 wildcards( “ > ” , “ | ”和“ * ”等 ) 如果想用的话,必须得重新启动一个新 shell(在 spawn 的参数 command 中是不会解释他们的,视其为 command string 的一个普通字符)

清单 9. 重新启动一个 shell 来规避 pexpect 对元字符的不解释

如果想在 spawn 出来的新子程序中使用重定向 redirect,管道 pipe,和通配符 wildcards( “ > ” , “ | ”和“ * ”等 ),好像没有好的方法,只能不使用这些字符,先利用 expect 匹配命令提示符,从而在 before 中可以拿到之前命令的结果,然后在分析 before 的内容达到使用重定向 redirect, 管道 pipe, 和通配符 wildcards 的目的。

EOF 异常和 TIMEOUT 异常

TIMEOUT 异常

如果子程序没有在指定的时间内生成任何 output,那么 expect() 和 read() 都会产生 TIMEOUT 异常。超时默认是 30s,可以在 expect() 和 spawn 构造函数初始化时指定为其它时间,如:

如果你想让 expect() 和 read() 忽略超时限制,即无限期阻塞住直到有 output 产生,设置 timeout 参数为 None。

清单 10. 忽略 timeout 超时限制的例子代码

EOF 异常

可能会有两种 EOF 异常被抛出,但是他们除了显示的信息不同,其实本质上是相同的。为了实用的目的,不需要区分它们,他们只是给了些关于你的 python 程序到底运行在哪个平台上的额外信息,这两个显示信息是:

有些 UNIX 平台,当你读取一个处于 EOF 状态的文件描述符时,会抛出异常,其他 UNIX 平台,却只会静静地返回一个空字符串来表明该文件已经达到了状态。

使用 run() 来替代某些的 spawn 的使用

pexpect 模块除了提供 spawn 类以外,还提供了 run() 函数,使用其可以取代一些 spawn 的使用,而且更加简单明了。

清单 11. 使用 run() 来替代 spawn 的使用的例子代码

run (command, timeout=-1, withexitstatus=False, events=None, extra_args=None, logfile=None, cwd=None, env=None):

command:执行一个命令,然后返回结果,run() 可以替换 os.system()(更多 os.system() 知识,请参阅参考资料),因为 os.system() 得不到命令输出的结果

返回的 output 是个字符串,STDERR 也会包括在 output 中,如果全路径没有被指定,那么 path 会被 search

timeout:单位 s 秒,每隔 timeout 生成一个 pexpect.TIMEOUT 异常

每行之间被 CR/LF (\\r\\n) 相隔,即使在 Unix 平台上也是 CR/LF,因为 Pexpect 子程序是伪 tty 设备

withexitstatus:设置为 True,则返回一个 tuple,里面包括 (command_output, exitstatus),如果其为 False,那么只是仅仅返回 command_output

events:是个 dictionary,里面存放 {pattern:response} 。无论什么时候 pattern 在命令的结果中出现了,会出现以下动作:

发送相应的 response String 。如果需要回车符“ Enter ”的话,“ \\n ”也必须得出现在 response 字符串中。

response 同样也可以是个回调函数,不过该回调函数有特殊要求,即它的参数必须是个 dictionary,该 dictionary 的内容是:包含所有在 run() 中定义的局部变量,从而提供了方法可以访问 run() 函数中 spawn 生成的子程序和 run() 中定义的其他局部变量,其中 event_count, child, 和 extra_args 最有用。回调函数可能返回 True,从而阻止当前 run() 继续执行,否则 run() 会继续执行直到下一个 event 。回调函数也可能返回一个字符串,然后被发送给子程序。 'extra_args' 不是直接被 run() 使用,它只是提供了一个方法可以通过 run() 来将数据传入到回调函数中(其实是通过 run() 定义的局部变量 dictionary 来传)

清单 12. 其它一些使用 run() 的例子代码

expect_exact() 的使用

expect_exact(self, pattern_list, timeout = -1, searchwindowsize = -1); expect_exact() 与 expect() 类似,但是 pattern_list 只能是字符串或者是一个字符串的 list,不能是正则表达式,其匹配速度会快于 expect(),原因有两个:一是字符串的 search 比正则表达式的匹配要快,另一个则是可以限制只从输入缓冲的结尾来寻找匹配的字符串。还有当你觉得每次要 escape 正则表达式中的特殊字符为普通字符时很烦,那么你也可以使用 expect_exact() 来取代 expect()。

清单 13. expect_exact() 的例子代码

expect() 中正则表达式的使用 tips

expect() 中的正则表达式不是贪婪匹配 greedy match,而是最小匹配,即只匹配缓冲区中最早出现的第一个字符串。 因为是依次读取一个字符的 stream 流来判断是否和正则表达式所表达的模式匹配,所以如果参数 pattern 是个 list,而且不止一次匹配,那么缓冲区中最早出现的第一个匹配的字符串才算数。

清单 14. expect() 的最小匹配例子代码

“$”不起任何作用,匹配一行的结束 (end of line),必须得匹配 CR/LF

正则表达式中,'$'可以匹配一行的结束(具体'$'正则表达式的使用,请参阅参考资料),但是 pexpect 从子程序中一次只读取一个字符,而且每个字符都好像是一行的结束一样,pexpect 不能在子程序的输出流去预测。匹配一行结束的方法必须是匹配 "\r\n" (CR/LF) 。即使是 Unix 系统,也是匹配 "\r\n" (CR/LF),因为 pexpect 使用一个 Pseudo-TTY 设备与子程序通话,所以当子程序输出 "\n" 你仍然会在 python 主程序中看到 "\r\n" 。原因是 TTY 设备更像 windows 操作系统,每一行结束都有个 "\r\n" (CR/LF) 的组合,当你从 TTY 设备去解释一个 Unix 的命令时,你会发现真正的输出是 "\r\n" (CR/LF),一个 Unix 命令只会写入一个 linefeed (\n),但是 TTY 设备驱动会将其转换成 "\r\n" (CR/LF) 。

清单 15. 匹配一行结束 1

如果你只是想跳过一个新行,直接 expect('\n') 就可以了,但是如果你想在一行的结束匹配一个具体的 pattern 时,就必须精确的寻找 (\r),见下例:

清单 16. 匹配一行结束 2

这个问题其实不只是 pexpect 会有,如果你在一个 stream 流上实施正则表达式匹配时,都会遇到此问题。正则表达式需要预测,stream 流中很难预测,因为生成这个流的进程可能还没有结束,所以你很难知道是否该进程是暂时性的暂停还是已经彻底结束。

当 '.' 和 '*' 出现在最后时

child.expect ('.+'); 因为是最小匹配,所以只会返回一个字符,而不是一个整个一行(虽然 pexpect 设置了 re.DOTALL,会匹配一个新行。 child.expect ('.*'); 每次匹配都会成功,但是总是没有字符返回,因为 '*' 表明前面的字符可以出现 0 次 , 在 pexpect 中,一般来说,任何 '*' 都会尽量少的匹配。

isalive() 的使用 tips

isalive(self)

测试子程序是否还在运行。这个方法是非阻塞的,如果子程序被终止了,那么该方法会去读取子程序的 exitstatus 或 signalstatus 这两个域。返回 True 表明子程序好像是在运行,返回 False 表示不再运行。当平台是 Solaris 时,可能需要几秒钟才能得到正确的状态。 当子程序退出后立马执行 isalive() 有时可能会返回 1 (True),这是一个 race condition,原因是子程序已经关闭了其文件描述符,但是在 isalive() 执行前还没有完全的退出。增加一个小小的延时会对 isalive() 的结果有效性有帮助。

清单 17. isalive() 的例子代码

delaybeforesend 的使用 tips

spawn 类的域 delaybeforesend 可以帮助克服一些古怪的行为。比如,经典的是,当一个用户使用 expect() 期待 "Password:" 提示符时,如果匹配,立马 sendline() 发送密码给子程序,但是这个用户会看到他们的密码被 echo back 回显回来了。这是因为,通常许多应用程序都会在打印出 "Password:" 提示符后,立马关掉 stdin 的 echo,但是如果你发送密码过快,在程序关掉 stdin 的 echo 之前就发送密码出去了,那么该密码就会被 echo 出来。

清单 18. delaybeforesend 的例子代码

相关主题

访问 Expect 的主页,了解更多 Expect 的内容。

访问 Python 官方网页,了解更多 Python 相关知识。

有关正则表达式方面相关知识,请访问正则表达式。

更多 SSH 相关知识,请访问 SSH。

更多 os.system() 的介绍,请访问 os.system()。

在 developerWorks 上查阅所有 Linux 技巧 和 Linux 教程。

参考帖子

python pp模块_Python模块--Pexpect相关推荐

  1. python 怎么安装电脑摄像头模块_Python模块及安装

    Python模块及安装 09-Python模块及安装思维导图下载 1.模块的使用及安装 <1>Python中的模块 在Python中有一个概念叫做模块(module),这个和C语言中的头文 ...

  2. python相对引用_Python 模块相对引用

    文件结构如下 python_directory/ ├── __init__.py └── app ├── __init__.py ├── sub1 │   ├── __init__.py │   └─ ...

  3. python模块调用模块_Python模块调用

    目录 1 模块 一个模块是包含了Python定义和声明的文件,文件名,就是模块名字加上py 后缀 把定义的函数.变量保存到文件中,通过Python test.py的方式执行,test.py就是脚本文件 ...

  4. python利用什么写模块_python模块是什么?写法及作用分析

    在这篇文章之中我们来了解一下python这门编程语言之中的模块.刚刚接触这门语言的朋友可能并不懂Python中的模块这个概念是什么意思.那么这篇文章就来带大家来认识一下模块.我们首先要知道python ...

  5. 如何查看python安装了哪些模块_Python模块如何安装 并确认模块已经安装好?

    看自己有没有安装好,最简单的办法在可以再控制台下: C:\Users\sony>python Python 2.7.6 (default, Nov 10 2013, 19:24:18) [MSC ...

  6. import pymysql 没有模块_python模块与包

    模块的概念 •模块是一个保存了Python代码的文件,其中可以包含变量.函数或类的定义,也可以包含其他各种Python语句.使用模块有以下3方面的优势. •(1)模块提高了代码的可维护性.在程序开发过 ...

  7. python zipfile教程_Python模块zipfile原理及使用方法详解

    zipfile是python里用来做zip格式编码的压缩和解压缩的,由于是很常见的zip格式,所以这个模块使用频率也是比较高的 zipfile里有两个非常重要的class, 分别是ZipFile和Zi ...

  8. python存文件的模块_python模块之StringIO/cStringIO(内存文件)

    1. StringIO/cStringIO是什么 这个模块提供了一个类,这个类的实例就像是一个文件一样可以读写,实际上读写的是一个字符串缓存,也可以称之为内存文件. StringIO和文件对象拥有共同 ...

  9. python从其他文件导入模块_Python模块可以使用其他文件的导入吗?

    我有这样的事情: # a.py import os class A: ... # b.py import a class B(A): ... 在B类(b.py)中,我希望能够使用在a.py中导入的模块 ...

最新文章

  1. windows mobile设置插移动卡没反应_ipad pro外接移动硬盘ipados
  2. stm32 工业按键检测_「正点原子STM32Mini板资料连载」第七章 按键输入实验
  3. 分享Kali Linux 2016.2第50周虚拟机
  4. ASP.NET Core 中断请求了解一下(翻译)
  5. linux 进城 管道丢数据,linux – 使用命名管道与bash – 数据丢失的问题
  6. Vue3 slot插槽——(默认插槽、具名插槽、作用域插槽)
  7. 2019年春季学期第九周作业
  8. android textview基线,Textview画文字基线的问题
  9. Competitive Programming专题题解(1)
  10. Exchange2003/2010共存模式环境迁移
  11. 如何改善字幕组同学「为爱发电」的工作环境?
  12. Pandas系列(十三)分层索引MultiIndex
  13. 有关计算机的未来想象作文,电脑的想象作文
  14. html形状圆形,html – 使用CSS的圆形标记形状
  15. 电脑桌面下栏和计算机里面全黑,电脑桌面下面菜单栏变黑条了,为什么?
  16. 设计模式:设计模式经典总结
  17. php过滤微信表情符号
  18. 数据库SQL的高级查询
  19. 【基于TCP的在线词典】
  20. matlab 三分之一倍频程,三分之一倍频程谱

热门文章

  1. ASP.NET Core 进程外(out-of-process)托管(7)《从零开始学ASP.NET CORE MVC》
  2. 首届大湾区 DevOps/微服务秋季分享会圆满落幕!
  3. 谈谈.NET Core中基于Generic Host来实现后台任务
  4. 迁移数据库到SQL on Linux Docker
  5. python 图像识别pytesseract快速设置
  6. [转]一文读懂目标检测:R-CNN、Fast R-CNN、Faster R-CNN、YOLO、SSD
  7. 【三维激光扫描】实验01:环境搭建CAD2014+StonexSiScan软件安装
  8. Java连接SQL Server类MyDBase的实现
  9. Android之华为手机打开app奔溃提示java.io.FileNotFoundException: res/drawable/abc_vector_test.xml
  10. Android之如何实现阿拉伯版本(RTL)的recycleView的网格布局