1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
// An example is based on README.md from https://github.com/philippkeller/rexpect

#[cfg(unix)]
use expectrl::{repl::spawn_bash, ControlCode, Regex};

#[cfg(unix)]
#[cfg(not(feature = "async"))]
fn main() {
    let mut p = spawn_bash().unwrap();

    // case 1: execute
    let hostname = p.execute("hostname").unwrap();
    println!("Current hostname: {:?}", String::from_utf8_lossy(&hostname));

    // case 2: wait until done, only extract a few infos
    p.send_line("wc /etc/passwd").unwrap();
    // `exp_regex` returns both string-before-match and match itself, discard first
    let lines = p.expect(Regex("[0-9]+")).unwrap();
    let words = p.expect(Regex("[0-9]+")).unwrap();
    let bytes = p.expect(Regex("[0-9]+")).unwrap();
    p.expect_prompt().unwrap(); // go sure `wc` is really done
    println!(
        "/etc/passwd has {} lines, {} words, {} chars",
        String::from_utf8_lossy(&lines[0]),
        String::from_utf8_lossy(&words[0]),
        String::from_utf8_lossy(&bytes[0]),
    );

    // case 3: read while program is still executing
    p.send_line("ping 8.8.8.8").unwrap(); // 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.expect(Regex("[0-9. ]+ ms")).unwrap();
        println!("Roundtrip time: {}", String::from_utf8_lossy(&duration[0]));
    }

    p.send(ControlCode::EOT).unwrap();
}

#[cfg(unix)]
#[cfg(feature = "async")]
fn main() {
    use futures_lite::io::AsyncBufReadExt;

    futures_lite::future::block_on(async {
        let mut p = spawn_bash().await.unwrap();

        // case 1: wait until program is done
        p.send_line("hostname").await.unwrap();
        let mut hostname = String::new();
        p.read_line(&mut hostname).await.unwrap();
        p.expect_prompt().await.unwrap(); // go sure `hostname` is really done
        println!("Current hostname: {hostname:?}"); // it prints some undetermined characters before hostname ...

        // case 2: wait until done, only extract a few infos
        p.send_line("wc /etc/passwd").await.unwrap();
        // `exp_regex` returns both string-before-match and match itself, discard first
        let lines = p.expect(Regex("[0-9]+")).await.unwrap();
        let words = p.expect(Regex("[0-9]+")).await.unwrap();
        let bytes = p.expect(Regex("[0-9]+")).await.unwrap();
        p.expect_prompt().await.unwrap(); // go sure `wc` is really done
        println!(
            "/etc/passwd has {} lines, {} words, {} chars",
            String::from_utf8_lossy(lines.get(0).unwrap()),
            String::from_utf8_lossy(words.get(0).unwrap()),
            String::from_utf8_lossy(bytes.get(0).unwrap()),
        );

        // case 3: read while program is still executing
        p.send_line("ping 8.8.8.8").await.unwrap(); // 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.expect(Regex("[0-9. ]+ ms")).await.unwrap();
            println!(
                "Roundtrip time: {}",
                String::from_utf8_lossy(duration.get(0).unwrap())
            );
        }

        p.send(ControlCode::EOT).await.unwrap();
    })
}

#[cfg(windows)]
fn main() {
    panic!("An example doesn't supported on windows")
}