[−][src]Crate tokio_process
An implementation of asynchronous process management for Tokio.
This crate provides a CommandExt
trait to enhance the functionality of the
Command
type in the standard library. The three methods provided by this
trait mirror the "spawning" methods in the standard library. The
CommandExt
trait in this crate, though, returns "future aware" types that
interoperate with Tokio. The asynchronous process support is provided
through signal handling on Unix and system APIs on Windows.
Examples
Here's an example program which will spawn echo hello world
and then wait
for it complete.
#![feature(async_await)] use std::process::Command; use tokio_process::CommandExt; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { // Use the standard library's `Command` type to build a process and // then execute it via the `CommandExt` trait. let child = Command::new("echo").arg("hello").arg("world") .spawn_async(); // Make sure our child succeeded in spawning and process the result let future = child.expect("failed to spawn"); // Await until the future (and the command) completes let status = future.await?; println!("the command exited with: {}", status); Ok(()) }
Next, let's take a look at an example where we not only spawn echo hello world
but we also capture its output.
#![feature(async_await)] use std::process::Command; use tokio_process::CommandExt; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { // Like above, but use `output_async` which returns a future instead of // immediately returning the `Child`. let output = Command::new("echo").arg("hello").arg("world") .output_async(); let output = output.await?; assert!(output.status.success()); assert_eq!(output.stdout, b"hello world\n"); Ok(()) }
We can also read input line by line.
#![feature(async_await)] use futures_util::stream::StreamExt; use std::process::{Command, Stdio}; use tokio::codec::{FramedRead, LinesCodec}; use tokio_process::CommandExt; #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { let mut cmd = Command::new("cat"); // Specify that we want the command's standard output piped back to us. // By default, standard input/output/error will be inherited from the // current process (for example, this means that standard input will // come from the keyboard and standard output/error will go directly to // the terminal if this process is invoked from the command line). cmd.stdout(Stdio::piped()); let mut child = cmd.spawn_async() .expect("failed to spawn command"); let stdout = child.stdout().take() .expect("child did not have a handle to stdout"); let mut reader = FramedRead::new(stdout, LinesCodec::new()); // Ensure the child process is spawned in the runtime so it can // make progress on its own while we await for any output. tokio::spawn(async { let status = child.await .expect("child process encountered an error"); println!("child status was: {}", status); }); while let Some(line) = reader.next().await { println!("Line: {}", line?); } Ok(()) }
Caveats
While similar to the standard library, this crate's Child
type differs
importantly in the behavior of drop
. In the standard library, a child
process will continue running after the instance of std::process::Child
is dropped. In this crate, however, because tokio_process::Child
is a
future of the child's ExitStatus
, a child process is terminated if
tokio_process::Child
is dropped. The behavior of the standard library can
be regained with the Child::forget
method.
Structs
Child | Representation of a child process spawned onto an event loop. |
ChildStderr | The standard error stream for spawned children. |
ChildStdin | The standard input stream for spawned children. |
ChildStdout | The standard output stream for spawned children. |
OutputAsync | Future returned by the |
StatusAsync | Future returned by the |
WaitWithOutput | Future returned from the |
Traits
CommandExt | Extensions provided by this crate to the |