pub struct Child {
pub stdin: Option<ChildStdin>,
pub stdout: Option<ChildStdout>,
pub stderr: Option<ChildStderr>,
/* private fields */
}展开描述
在事件循环上派生的子进程的表示。
§Caveats
与标准库的行为类似,与 future 范式的“drop 即取消”不同,默认情况下,
派生出的进程即使在 Child 句柄被 drop 后仍会继续执行。
Command::kill_on_drop 方法可用于修改此行为,
当 Child 包装器在子进程退出前被 drop 时终止子进程。
字段§
§stdin: Option<ChildStdin>用于向子进程的标准输入(stdin)写入的句柄(如果已捕获)。
为了避免在使用 stdin 时部分移动 child,
从而无法在 child 上调用其它函数,
你可能会发现下面的写法很有帮助:
let stdin = child.stdin.take().unwrap();stdout: Option<ChildStdout>用于从子进程的标准输出(stdout)读取的句柄(如果已捕获)。你可能会发现下面的写法很有帮助
let stdout = child.stdout.take().unwrap();即在使用 stdout 时避免部分移动 child,
从而无法在 child 上调用其它函数。
stderr: Option<ChildStderr>用于从子进程的标准错误(stderr)读取的句柄(如果已捕获)。你可能会发现下面的写法很有帮助
let stderr = child.stderr.take().unwrap();即在使用 stderr 时避免部分移动 child,
从而无法在 child 上调用其它函数。
实现§
Source§impl Child
impl Child
Sourcepub fn id(&self) -> Option<u32>
pub fn id(&self) -> Option<u32>
在子进程仍在运行时,返回由操作系统分配的与此子进程关联的进程标识符。
子进程被 poll 完成之后,此方法将返回 None。
这是为了避免在 Unix 等操作系统上出现混淆 ——
进程完成后操作系统标识符可能被复用。
Sourcepub fn raw_handle(&self) -> Option<RawHandle>
pub fn raw_handle(&self) -> Option<RawHandle>
提取与此子进程关联的进程原始句柄(仅在子进程仍在运行时有效)。
如果子进程已退出,则返回 None。
Sourcepub fn start_kill(&mut self) -> Result<()>
pub fn start_kill(&mut self) -> Result<()>
尝试强制子进程退出,但不会等待该请求生效。
在 Unix 平台上,这等效于发送 SIGKILL 信号。
注意在 Unix 平台上,kill 信号发出后仍可能残留僵尸进程;
为避免这种情况,调用者应确保成功调用 child.wait().await
或 child.try_wait()。
Sourcepub async fn kill(&mut self) -> Result<()>
pub async fn kill(&mut self) -> Result<()>
强制子进程退出。
这等同于在 unix 平台上发送 SIGKILL 信号,
随后调用 wait。
注意:标准库的 Child::kill 不会 wait。
若要在标准库中等价于 Child::kill 的行为,
请使用 start_kill。
§示例
如果需要远程终止子进程,可以结合使用 select! 宏和 oneshot 通道来实现。
在下面的示例中,除非向 oneshot 通道发送消息,否则子进程将一直运行到完成。
一旦收到消息,子进程会通过 .kill() 方法被立即终止。
use tokio::process::Command;
use tokio::sync::oneshot::channel;
#[tokio::main]
async fn main() {
let (send, recv) = channel::<()>();
let mut child = Command::new("sleep").arg("1").spawn().unwrap();
tokio::spawn(async move { send.send(()) });
tokio::select! {
_ = child.wait() => {}
_ = recv => child.kill().await.expect("kill failed"),
}
}你还可以与子进程的标准 I/O 交互。 例如,你可以在等待子进程退出的同时读取它的 stdout。
#[tokio::main]
async fn main() {
let (_tx, rx) = channel::<()>();
let mut child = Command::new("echo")
.arg("Hello World!")
.stdout(Stdio::piped())
.spawn()
.unwrap();
let mut stdout = child.stdout.take().expect("stdout is not captured");
let read_stdout = tokio::spawn(async move {
let mut buff = Vec::new();
let _ = stdout.read_to_end(&mut buff).await;
buff
});
tokio::select! {
_ = child.wait() => {}
_ = rx => { child.kill().await.expect("kill failed") },
}
let buff = read_stdout.await.unwrap();
assert_eq!(buff, b"Hello World!\n");
}Sourcepub async fn wait(&mut self) -> Result<ExitStatus>
pub async fn wait(&mut self) -> Result<ExitStatus>
等待子进程完全退出,返回其退出状态。 该函数在至少被调用一次之后,仍会返回相同的返回值。
到子进程的 stdin 句柄(如有)在等待之前会被关闭。 这有助于避免死锁:它确保子进程不会因为等待父进程的输入而阻塞, 同时父进程正在等待子进程退出。
如果调用者希望显式控制子进程 stdin 句柄关闭的时机,
可以在调用 .wait() 之前先调用 .take():
§Cancel safety
此函数是可取消安全的。
use tokio::io::AsyncWriteExt;
use tokio::process::Command;
use std::process::Stdio;
#[tokio::main]
async fn main() {
let mut child = Command::new("cat")
.stdin(Stdio::piped())
.spawn()
.unwrap();
let mut stdin = child.stdin.take().unwrap();
tokio::spawn(async move {
// do something with stdin here...
stdin.write_all(b"hello world\n").await.unwrap();
// then drop when finished
drop(stdin);
});
// wait for the process to complete
let _ = child.wait().await;
}Sourcepub fn try_wait(&mut self) -> Result<Option<ExitStatus>>
pub fn try_wait(&mut self) -> Result<Option<ExitStatus>>
如果子进程已退出,尝试收集其退出状态。
该函数不会阻塞调用线程,只会检查子进程是否已退出。 如果子进程已退出,在 Unix 上将回收其进程 ID。 只要子进程已经退出,此函数保证能反复返回成功的退出状态。
如果子进程已退出,则返回 Ok(Some(status))。
如果此时退出状态不可用,则返回 Ok(None)。
如果发生错误,则返回该错误。
注意,与 wait 不同,此函数不会尝试 drop stdin,
也不会在子进程退出时唤醒当前任务。
Sourcepub async fn wait_with_output(self) -> Result<Output>
pub async fn wait_with_output(self) -> Result<Output>
返回一个 future,它将解析为一个 Output,
其中包含子进程的退出状态、stdout 和 stderr。
返回的 future 会同时等待子进程退出,
并收集 stdout/stderr 句柄上所有剩余的输出,
最终返回一个 Output 实例。
到子进程的 stdin 句柄(如有)在等待之前会被关闭。 这有助于避免死锁:它确保子进程不会因为等待父进程的输入而阻塞, 同时父进程正在等待子进程退出。
默认情况下,stdin、stdout 和 stderr 继承自父进程。
要将输出捕获到此 Output 中,需要在父子进程之间创建新的管道。
创建 Command 时可分别使用 stdout(Stdio::piped())
或 stderr(Stdio::piped())。