6 个版本 (重大更新)
0.5.0 | 2022 年 10 月 20 日 |
---|---|
0.4.0 | 2020 年 5 月 25 日 |
0.3.0 | 2018 年 2 月 25 日 |
0.2.0 | 2017 年 9 月 27 日 |
0.1.0 | 2017 年 7 月 27 日 |
#67 in Unix API
每月 20,788 次下载
在 36 个 crate 中使用 (直接使用 34 个)
53KB
785 行
rexpect
启动、控制和响应子应用程序和进程的预期模式,从而实现交互自动化和测试。组件包括
- session:启动新进程并与它交互;rexpect 的主要模块。
- reader:非阻塞读取器,支持等待字符串、正则表达式和 EOF。
- process:在 pty 中启动进程。
目标是提供与 pexpect 相似的功能集。
示例
基本用法
将此添加到您的 Cargo.toml
[dependencies]
rexpect = "0.4"
通过 ftp 交互的简单示例
extern crate rexpect;
use rexpect::spawn;
use rexpect::errors::*;
fn do_ftp() -> Result<()> {
let mut p = spawn("ftp speedtest.tele2.net", Some(30_000))?;
p.exp_regex("Name \\(.*\\):")?;
p.send_line("anonymous")?;
p.exp_string("Password")?;
p.send_line("test")?;
p.exp_string("ftp>")?;
p.send_line("cd upload")?;
p.exp_string("successfully changed.\r\nftp>")?;
p.send_line("pwd")?;
p.exp_regex("[0-9]+ \"/upload\"")?;
p.send_line("exit")?;
p.exp_eof()?;
Ok(())
}
fn main() {
do_ftp().unwrap_or_else(|e| panic!("ftp job failed with {}", e));
}
与 bash 和读取程序结合的示例
extern crate rexpect;
use rexpect::spawn_bash;
use rexpect::errors::*;
fn do_bash() -> Result<()> {
let mut p = spawn_bash(Some(2000))?;
// case 1: wait until program is done
p.send_line("hostname")?;
let hostname = p.read_line()?;
p.wait_for_prompt()?; // go sure `hostname` is really done
println!("Current hostname: {}", hostname);
// case 2: wait until done, only extract a few infos
p.send_line("wc /etc/passwd")?;
// `exp_regex` returns both string-before-match and match itself, discard first
let (_, lines) = p.exp_regex("[0-9]+")?;
let (_, words) = p.exp_regex("[0-9]+")?;
let (_, bytes) = p.exp_regex("[0-9]+")?;
p.wait_for_prompt()?; // go sure `wc` is really done
println!("/etc/passwd has {} lines, {} words, {} chars", lines, words, bytes);
// case 3: read while program is still executing
p.execute("ping 8.8.8.8", "bytes of data")?; // returns when it sees "bytes of data" in output
for _ in 0..5 {
// times out if one ping takes longer than 2s
let (_, duration) = p.exp_regex("[0-9. ]+ ms")?;
println!("Roundtrip time: {}", duration);
}
p.send_control('c')?;
Ok(())
}
fn main() {
do_bash().unwrap_or_else(|e| panic!("bash job failed with {}", e));
}
与 bash 和作业控制结合的示例
发送 ctrl-c 和类似操作时,一个常见的问题是需要确保程序已完全加载,否则 ctrl-* 将进入虚无之地。有两个函数可以确保这一点
execute
其中您需要提供一个匹配字符串,当程序准备好时该字符串出现在 stdout/stderr 上wait_for_prompt
它等待提示再次出现
extern crate rexpect;
use rexpect::spawn_bash;
use rexpect::errors::*;
fn do_bash_jobcontrol() -> Result<()> {
let mut p = spawn_bash(Some(1000))?;
p.execute("ping 8.8.8.8", "bytes of data")?;
p.send_control('z')?;
p.wait_for_prompt()?;
// bash writes 'ping 8.8.8.8' to stdout again to state which job was put into background
p.execute("bg", "ping 8.8.8.8")?;
p.wait_for_prompt()?;
p.send_line("sleep 0.5")?;
p.wait_for_prompt()?;
// bash writes 'ping 8.8.8.8' to stdout again to state which job was put into foreground
p.execute("fg", "ping 8.8.8.8")?;
p.send_control('c')?;
p.exp_string("packet loss")?;
Ok(())
}
fn main() {
do_bash_jobcontrol().unwrap_or_else(|e| panic!("bash with job control failed with {}", e));
}
项目状态
Rexpect 涵盖了 pexpect 的几乎所有功能。如果您缺少任何功能,我非常乐意接收 PR 或 Issue 请求。
测试涵盖了大多数方面,并且应该可以在 Linux 或 Mac 上针对 rust stable、beta 和 nightly 运行。
设计决策
- 使用 error-chain 的错误处理
- 使用 nix(尽可能避免 libc)以保持代码的安全和整洁
- 遗憾的是,在Rust中,
expect
被过度使用来解包Option
和Result
,请使用exp_*
代替
许可协议:MIT 许可协议
依赖项
~5–15MB
~209K SLoC