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
impl PtyProcess
Sourcepub fn spawn(command: Command) -> Result<Self>
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?
5fn main() -> Result<()> {
6 // spawn a cat process
7 let mut process = PtyProcess::spawn(Command::new("cat"))?;
8
9 // create a communication stream
10 let mut stream = process.get_raw_handle()?;
11
12 // send a message to process
13 writeln!(stream, "Hello cat")?;
14
15 // read a line from the stream
16 let mut reader = BufReader::new(stream);
17 let mut buf = String::new();
18 reader.read_line(&mut buf)?;
19
20 println!("line was entered {buf:?}");
21
22 // stop the process
23 assert!(process.exit(true)?);
24
25 Ok(())
26}More examples
9fn main() {
10 let mut cmd = Command::new("find");
11 cmd.args(vec!["/home/", "-name", "foo"]);
12 cmd.stderr(std::process::Stdio::null());
13
14 let process = PtyProcess::spawn(cmd).unwrap();
15 let mut reader = BufReader::new(process.get_raw_handle().unwrap());
16
17 let mut buf = String::new();
18 loop {
19 let n = reader.read_line(&mut buf).expect("readline error");
20 if n == 0 {
21 break;
22 }
23
24 // by -1 we drop \n.
25 let text = &buf[0..buf.len() - 1];
26 println!("buffer: {text}");
27
28 buf.clear();
29 }
30}8fn main() {
9 let process = PtyProcess::spawn(Command::new("cat")).expect("Error while spawning process");
10 let mut stream = process
11 .get_pty_stream()
12 .expect("Failed to get a pty handle");
13
14 let mut this_file = File::open(".gitignore").expect("Can't open a file");
15 io::copy(&mut this_file, &mut stream).expect("Can't copy a file");
16
17 // EOT
18 stream
19 .write_all(&[4])
20 .expect("Error while exiting a process");
21
22 // We can't read_to_end as the process isn't DEAD but at time time it is it's already a EOF
23
24 let mut buf = [0; 128];
25 loop {
26 let n = stream.read(&mut buf).expect("Erorr on read");
27 print!("{}", String::from_utf8_lossy(&buf[..n]));
28
29 if n == 0 {
30 break;
31 }
32 }
33}Sourcepub fn get_raw_handle(&self) -> Result<File>
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?
5fn main() -> Result<()> {
6 // spawn a cat process
7 let mut process = PtyProcess::spawn(Command::new("cat"))?;
8
9 // create a communication stream
10 let mut stream = process.get_raw_handle()?;
11
12 // send a message to process
13 writeln!(stream, "Hello cat")?;
14
15 // read a line from the stream
16 let mut reader = BufReader::new(stream);
17 let mut buf = String::new();
18 reader.read_line(&mut buf)?;
19
20 println!("line was entered {buf:?}");
21
22 // stop the process
23 assert!(process.exit(true)?);
24
25 Ok(())
26}More examples
9fn main() {
10 let mut cmd = Command::new("find");
11 cmd.args(vec!["/home/", "-name", "foo"]);
12 cmd.stderr(std::process::Stdio::null());
13
14 let process = PtyProcess::spawn(cmd).unwrap();
15 let mut reader = BufReader::new(process.get_raw_handle().unwrap());
16
17 let mut buf = String::new();
18 loop {
19 let n = reader.read_line(&mut buf).expect("readline error");
20 if n == 0 {
21 break;
22 }
23
24 // by -1 we drop \n.
25 let text = &buf[0..buf.len() - 1];
26 println!("buffer: {text}");
27
28 buf.clear();
29 }
30}Sourcepub fn get_pty_stream(&self) -> Result<Stream>
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?
8fn main() {
9 let process = PtyProcess::spawn(Command::new("cat")).expect("Error while spawning process");
10 let mut stream = process
11 .get_pty_stream()
12 .expect("Failed to get a pty handle");
13
14 let mut this_file = File::open(".gitignore").expect("Can't open a file");
15 io::copy(&mut this_file, &mut stream).expect("Can't copy a file");
16
17 // EOT
18 stream
19 .write_all(&[4])
20 .expect("Error while exiting a process");
21
22 // We can't read_to_end as the process isn't DEAD but at time time it is it's already a EOF
23
24 let mut buf = [0; 128];
25 loop {
26 let n = stream.read(&mut buf).expect("Erorr on read");
27 print!("{}", String::from_utf8_lossy(&buf[..n]));
28
29 if n == 0 {
30 break;
31 }
32 }
33}Sourcepub fn get_eof_char(&self) -> u8
pub fn get_eof_char(&self) -> u8
Get a end of file character if set or a default.
Sourcepub fn get_intr_char(&self) -> u8
pub fn get_intr_char(&self) -> u8
Get a interapt character if set or a default.
Sourcepub fn get_window_size(&self) -> Result<(u16, u16)>
pub fn get_window_size(&self) -> Result<(u16, u16)>
Get window size of a terminal.
Default size is 80x24.
Sourcepub fn set_echo(&mut self, on: bool, timeout: Option<Duration>) -> Result<bool>
pub fn set_echo(&mut self, on: bool, timeout: Option<Duration>) -> Result<bool>
Sets a echo setting for a terminal
Sourcepub fn set_terminate_delay(&mut self, terminate_approach_delay: Duration)
pub fn set_terminate_delay(&mut self, terminate_approach_delay: Duration)
Set the pty process’s terminate approach delay.
Sourcepub fn status(&self) -> Result<WaitStatus>
pub fn status(&self) -> Result<WaitStatus>
Status returns a status a of child process.
Sourcepub fn kill(&mut self, signal: Signal) -> Result<()>
pub fn kill(&mut self, signal: Signal) -> Result<()>
Kill sends a signal to a child process.
The operation is non-blocking.
Sourcepub fn wait(&self) -> Result<WaitStatus>
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.
Sourcepub fn is_alive(&self) -> Result<bool>
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.
Sourcepub fn exit(&mut self, force: bool) -> Result<bool>
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.
- SIGHUP
- SIGCONT
- SIGINT
- SIGTERM
If “force” is true then moves onto SIGKILL.
Examples found in repository?
5fn main() -> Result<()> {
6 // spawn a cat process
7 let mut process = PtyProcess::spawn(Command::new("cat"))?;
8
9 // create a communication stream
10 let mut stream = process.get_raw_handle()?;
11
12 // send a message to process
13 writeln!(stream, "Hello cat")?;
14
15 // read a line from the stream
16 let mut reader = BufReader::new(stream);
17 let mut buf = String::new();
18 reader.read_line(&mut buf)?;
19
20 println!("line was entered {buf:?}");
21
22 // stop the process
23 assert!(process.exit(true)?);
24
25 Ok(())
26}