rexpect

Spawn, control, and respond to expected patterns of child applications and
processes, enabling the automation of interactions and testing. Components
include:
- session: start a new process and interact with it; primary module of
rexpect.
- reader: non-blocking reader, which supports waiting for strings, regex,
and EOF.
- process: spawn a process in a pty.
The goal is to offer a similar set of functionality as
pexpect.
Examples
For more examples, check the examples directory.
Basic usage
Simple example for interacting via ftp:
use rexpect::spawn;
use rexpect::error::*;
fn do_ftp() -> Result<(), Error> {
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));
}
Example with bash and reading from programs
use rexpect::spawn_bash;
use rexpect::error::*;
fn do_bash() -> Result<(), Error> {
let mut p = spawn_bash(Some(2000))?;
p.send_line("hostname")?;
let hostname = p.read_line()?;
p.wait_for_prompt()?; println!("Current hostname: {}", hostname);
p.send_line("wc /etc/passwd")?;
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()?; println!("/etc/passwd has {} lines, {} words, {} chars", lines, words, bytes);
p.execute("ping 8.8.8.8", "bytes of data")?; for _ in 0..5 {
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));
}
Example with bash and job control
One frequent bitfall with sending ctrl-c and friends is that you need
to somehow ensure that the program has fully loaded, otherwise the ctrl-*
goes into nirvana. There are two functions to ensure that:
execute
where you need to provide a match string which is present
on stdout/stderr when the program is ready
wait_for_prompt
which waits until the prompt is shown again
use rexpect::spawn_bash;
use rexpect::error::*;
fn do_bash_jobcontrol() -> Result<(), Error> {
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()?;
p.execute("bg", "ping 8.8.8.8")?;
p.wait_for_prompt()?;
p.send_line("sleep 0.5")?;
p.wait_for_prompt()?;
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));
}
License
Licensed under either of
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally
submitted for inclusion in the work by you, as defined in the Apache-2.0
license, shall be dual licensed as above, without any additional terms or
conditions.