spawn_bash

Function spawn_bash 

Source
pub fn spawn_bash(timeout: Option<u64>) -> Result<PtyReplSession, Error>
Expand description

Spawn bash in a pty session, run programs and expect output

The difference to spawn and spawn_command is:

  • spawn_bash starts bash with a custom rcfile which guarantees a certain prompt
  • the PtyBashSession also provides wait_for_prompt and execute

timeout: the duration until which exp_* returns a timeout error, or None additionally, when dropping the bash prompt while bash is still blocked by a program (e.g. sleep 9999) then the timeout is used as a timeout before a kill -9 is issued at the bash command. Use a timeout whenever possible because it makes debugging a lot easier (otherwise the program just hangs and you don’t know where)

bash is started with echo off. That means you don’t need to “read back” what you wrote to bash. But what you need to do is a wait_for_prompt after a process finished.

Also: if you start a program you should use execute and not send_line.

For an example see the README

Examples found in repository?
examples/bash.rs (line 5)
4fn main() -> Result<(), Error> {
5    let mut p = spawn_bash(Some(1000))?;
6    p.execute("ping 8.8.8.8", "bytes")?;
7    p.send_control('z')?;
8    p.wait_for_prompt()?;
9    // bash writes 'ping 8.8.8.8' to stdout again to state which job was put into background
10    p.execute("bg", "ping 8.8.8.8")?;
11    p.wait_for_prompt()?;
12    p.send_line("sleep 0.5")?;
13    p.wait_for_prompt()?;
14    // bash writes 'ping 8.8.8.8' to stdout again to state which job was put into foreground
15    p.execute("fg", "ping 8.8.8.8")?;
16    p.send_control('c')?;
17    p.exp_string("packet loss")?;
18    Ok(())
19}
More examples
Hide additional examples
examples/bash_read.rs (line 5)
4fn main() -> Result<(), Error> {
5    let mut p = spawn_bash(Some(2000))?;
6
7    // case 1: wait until program is done
8    p.send_line("hostname")?;
9    let hostname = p.read_line()?;
10    p.wait_for_prompt()?; // go sure `hostname` is really done
11    println!("Current hostname: {hostname}");
12
13    // case 2: wait until done, only extract a few infos
14    p.send_line("wc /etc/passwd")?;
15    // `exp_regex` returns both string-before-match and match itself, discard first
16    let (_, lines) = p.exp_regex("[0-9]+")?;
17    let (_, words) = p.exp_regex("[0-9]+")?;
18    let (_, bytes) = p.exp_regex("[0-9]+")?;
19    p.wait_for_prompt()?; // go sure `wc` is really done
20    println!("/etc/passwd has {lines} lines, {words} words, {bytes} chars");
21
22    // case 3: read while program is still executing
23    p.execute("ping 8.8.8.8", "bytes of data")?; // returns when it sees "bytes of data" in output
24    for _ in 0..5 {
25        // times out if one ping takes longer than 2s
26        let (_, duration) = p.exp_regex("[0-9. ]+ ms")?;
27        println!("Roundtrip time: {duration}");
28    }
29    p.send_control('c')?;
30    Ok(())
31}