Struct ptyprocess::PtyProcess

source ·
pub struct PtyProcess { /* private fields */ }
Expand description

PtyProcess controls a spawned process and communication with this.

It implements std::io::Read and std::io::Write to communicate with a child.

use ptyprocess::PtyProcess;
use std::io::Write;
use std::process::Command;

let mut process = PtyProcess::spawn(Command::new("cat")).unwrap();
process.write_all(b"Hello World").unwrap();
process.flush().unwrap();

Implementations§

source§

impl PtyProcess

source

pub fn spawn(command: Command) -> Result<Self>

Spawns a child process and create a PtyProcess.

    let proc = PtyProcess::spawn(Command::new("bash"));
Examples found in repository?
examples/basic.rs (line 7)
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
fn main() -> Result<()> {
    // spawn a cat process
    let mut process = PtyProcess::spawn(Command::new("cat"))?;

    // create a communication stream
    let mut stream = process.get_raw_handle()?;

    // send a message to process
    writeln!(stream, "Hello cat")?;

    // read a line from the stream
    let mut reader = BufReader::new(stream);
    let mut buf = String::new();
    reader.read_line(&mut buf)?;

    println!("line was entered {buf:?}");

    // stop the process
    assert!(process.exit(true)?);

    Ok(())
}
More examples
Hide additional examples
examples/find.rs (line 14)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
fn main() {
    let mut cmd = Command::new("find");
    cmd.args(vec!["/home/", "-name", "foo"]);
    cmd.stderr(std::process::Stdio::null());

    let process = PtyProcess::spawn(cmd).unwrap();
    let mut reader = BufReader::new(process.get_raw_handle().unwrap());

    let mut buf = String::new();
    loop {
        let n = reader.read_line(&mut buf).expect("readline error");
        if n == 0 {
            break;
        }

        // by -1 we drop \n.
        let text = &buf[0..buf.len() - 1];
        println!("buffer: {text}");

        buf.clear();
    }
}
examples/cat.rs (line 9)
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
fn main() {
    let process = PtyProcess::spawn(Command::new("cat")).expect("Error while spawning process");
    let mut stream = process
        .get_pty_stream()
        .expect("Failed to get a pty handle");

    let mut this_file = File::open(".gitignore").expect("Can't open a file");
    io::copy(&mut this_file, &mut stream).expect("Can't copy a file");

    // EOT
    stream
        .write_all(&[4])
        .expect("Error while exiting a process");

    // We can't read_to_end as the process isn't DEAD but at time time it is it's already a EOF

    let mut buf = [0; 128];
    loop {
        let n = stream.read(&mut buf).expect("Erorr on read");
        print!("{}", String::from_utf8_lossy(&buf[..n]));

        if n == 0 {
            break;
        }
    }
}
source

pub fn pid(&self) -> Pid

Returns a pid of a child process

source

pub fn get_raw_handle(&self) -> Result<File>

Returns a file representation of a PTY, which can be used to communicate with a spawned process.

The file behaivor is platform dependent.

Safety

Be carefull changing a descriptors inner state (e.g fcntl) because it affects all structures which use it.

Be carefull using this method in async mode. Because descriptor is set to a non-blocking mode will affect all dublicated descriptors which may be unexpected.

Example
use ptyprocess::PtyProcess;
use std::{process::Command, io::{BufReader, LineWriter}};

let mut process = PtyProcess::spawn(Command::new("cat")).unwrap();
let pty = process.get_raw_handle().unwrap();
let mut writer = LineWriter::new(&pty);
let mut reader = BufReader::new(&pty);
Examples found in repository?
examples/basic.rs (line 10)
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
fn main() -> Result<()> {
    // spawn a cat process
    let mut process = PtyProcess::spawn(Command::new("cat"))?;

    // create a communication stream
    let mut stream = process.get_raw_handle()?;

    // send a message to process
    writeln!(stream, "Hello cat")?;

    // read a line from the stream
    let mut reader = BufReader::new(stream);
    let mut buf = String::new();
    reader.read_line(&mut buf)?;

    println!("line was entered {buf:?}");

    // stop the process
    assert!(process.exit(true)?);

    Ok(())
}
More examples
Hide additional examples
examples/find.rs (line 15)
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
fn main() {
    let mut cmd = Command::new("find");
    cmd.args(vec!["/home/", "-name", "foo"]);
    cmd.stderr(std::process::Stdio::null());

    let process = PtyProcess::spawn(cmd).unwrap();
    let mut reader = BufReader::new(process.get_raw_handle().unwrap());

    let mut buf = String::new();
    loop {
        let n = reader.read_line(&mut buf).expect("readline error");
        if n == 0 {
            break;
        }

        // by -1 we drop \n.
        let text = &buf[0..buf.len() - 1];
        println!("buffer: {text}");

        buf.clear();
    }
}
source

pub fn get_pty_stream(&self) -> Result<Stream>

Returns a stream representation of a PTY. Which can be used to communicate with a spawned process.

It differs from Self::get_raw_handle because it is platform independent.

Examples found in repository?
examples/cat.rs (line 11)
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
fn main() {
    let process = PtyProcess::spawn(Command::new("cat")).expect("Error while spawning process");
    let mut stream = process
        .get_pty_stream()
        .expect("Failed to get a pty handle");

    let mut this_file = File::open(".gitignore").expect("Can't open a file");
    io::copy(&mut this_file, &mut stream).expect("Can't copy a file");

    // EOT
    stream
        .write_all(&[4])
        .expect("Error while exiting a process");

    // We can't read_to_end as the process isn't DEAD but at time time it is it's already a EOF

    let mut buf = [0; 128];
    loop {
        let n = stream.read(&mut buf).expect("Erorr on read");
        print!("{}", String::from_utf8_lossy(&buf[..n]));

        if n == 0 {
            break;
        }
    }
}
source

pub fn get_eof_char(&self) -> u8

Get a end of file character if set or a default.

source

pub fn get_intr_char(&self) -> u8

Get a interapt character if set or a default.

source

pub fn get_window_size(&self) -> Result<(u16, u16)>

Get window size of a terminal.

Default size is 80x24.

source

pub fn set_window_size(&mut self, cols: u16, rows: u16) -> Result<()>

Sets a terminal size.

source

pub fn get_echo(&self) -> Result<bool>

The function returns true if an echo setting is setup.

source

pub fn set_echo(&mut self, on: bool, timeout: Option<Duration>) -> Result<bool>

Sets a echo setting for a terminal

source

pub fn isatty(&self) -> Result<bool>

Returns true if a underline fd connected with a TTY.

source

pub fn set_terminate_delay(&mut self, terminate_approach_delay: Duration)

Set the pty process’s terminate approach delay.

source

pub fn status(&self) -> Result<WaitStatus>

Status returns a status a of child process.

source

pub fn kill(&mut self, signal: Signal) -> Result<()>

Kill sends a signal to a child process.

The operation is non-blocking.

source

pub fn signal(&mut self, signal: Signal) -> Result<()>

Signal is an alias to PtyProcess::kill.

source

pub fn wait(&self) -> Result<WaitStatus>

Wait blocks until a child process exits.

It returns a error if the child was DEAD or not exist at the time of a call.

If you need to verify that a process is dead in non-blocking way you can use is_alive method.

source

pub fn is_alive(&self) -> Result<bool>

Checks if a process is still exists.

It’s a non blocking operation.

Keep in mind that after calling this method process might be marked as DEAD by kernel, because a check of its status. Therefore second call to Self::status or Self::is_alive might return a different status.

source

pub fn exit(&mut self, force: bool) -> Result<bool>

Try to force a child to terminate.

This returns true if the child was terminated. and returns false if the child could not be terminated.

It makes 4 tries getting more thorough.

  1. SIGHUP
  2. SIGCONT
  3. SIGINT
  4. SIGTERM

If “force” is true then moves onto SIGKILL.

Examples found in repository?
examples/basic.rs (line 23)
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
fn main() -> Result<()> {
    // spawn a cat process
    let mut process = PtyProcess::spawn(Command::new("cat"))?;

    // create a communication stream
    let mut stream = process.get_raw_handle()?;

    // send a message to process
    writeln!(stream, "Hello cat")?;

    // read a line from the stream
    let mut reader = BufReader::new(stream);
    let mut buf = String::new();
    reader.read_line(&mut buf)?;

    println!("line was entered {buf:?}");

    // stop the process
    assert!(process.exit(true)?);

    Ok(())
}

Trait Implementations§

source§

impl Debug for PtyProcess

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl Drop for PtyProcess

source§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

const: unstable · source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

const: unstable · source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

const: unstable · source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere U: From<T>,

const: unstable · source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
const: unstable · source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
const: unstable · source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.