gpt4 book ai didi

process - 我如何等待标准输出已通过管道传输到另一个的 Rust `Child` 进程?

转载 作者:行者123 更新时间:2023-11-29 08:26:27 25 4
gpt4 key购买 nike

我想实现是| head -n 1 在 Rust 中,正确连接管道并检查退出状态:即,我希望能够确定 yes 由于 SIGPIPE 而退出并且 head 完成通常情况下。管道功能很简单 ( Rust Playground ):

use std::process;

fn a() -> std::io::Result<()> {
let child_1 = process::Command::new("yes")
.arg("abracadabra")
.stdout(process::Stdio::piped())
.spawn()?;
let pipe: process::ChildStdout = child_1.stdout.unwrap();
let child_2 = process::Command::new("head")
.args(&["-n", "1"])
.stdin(pipe)
.stdout(process::Stdio::piped())
.spawn()?;
let output = child_2.wait_with_output()?;
let result = String::from_utf8_lossy(&output.stdout);
assert_eq!(result, "abracadabra\n");
println!("Good from 'a'.");
Ok(())
}

虽然我们可以随时等待 child_2,但声明pipe 移动 child_1,因此不清楚如何等待 child_1。如果我们简单地在 assert_eq! 之前添加 child_1.wait()?,我们会遇到编译时错误:

error[E0382]: borrow of moved value: `child_1`
--> src/main.rs:15:5
|
8 | let pipe: process::ChildStdout = child_1.stdout.unwrap();
| -------------- value moved here
...
15 | child_1.wait()?;
| ^^^^^^^ value borrowed here after partial move
|
= note: move occurs because `child_1.stdout` has type `std::option::Option<std::process::ChildStdout>`, which does not implement the `Copy` trait

我们可以设法等待 unsafe 和特定于平台的功能(Rust Playground):

use std::process;

fn b() -> std::io::Result<()> {
let mut child_1 = process::Command::new("yes")
.arg("abracadabra")
.stdout(process::Stdio::piped())
.spawn()?;
use std::os::unix::io::{AsRawFd, FromRawFd};
let pipe: process::Stdio =
unsafe { FromRawFd::from_raw_fd(child_1.stdout.as_ref().unwrap().as_raw_fd()) };
let mut child_2 = process::Command::new("head")
.args(&["-n", "1"])
.stdin(pipe)
.stdout(process::Stdio::piped())
.spawn()?;
println!("child_1 exited with: {:?}", child_1.wait().unwrap());
println!("child_2 exited with: {:?}", child_2.wait().unwrap());
let mut result_bytes: Vec<u8> = Vec::new();
std::io::Read::read_to_end(child_2.stdout.as_mut().unwrap(), &mut result_bytes)?;
let result = String::from_utf8_lossy(&result_bytes);
assert_eq!(result, "abracadabra\n");
println!("Good from 'b'.");
Ok(())
}

这打印:

child_1 exited with: ExitStatus(ExitStatus(13))
child_2 exited with: ExitStatus(ExitStatus(0))
Good from 'b'.

这对于这个问题的目的来说已经足够了,但肯定有必须是一种安全且便携的方式来执行此操作。

为了比较,下面是我将如何用 C 来处理这个任务(没有费心去捕获 child_2 的输出):

#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#define FAILIF(e, msg) do { if (e) { perror(msg); return 1; } } while (0)

void describe_child(const char *name, int status) {
if (WIFEXITED(status)) {
fprintf(stderr, "%s exited %d\n", name, WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
fprintf(stderr, "%s signalled %d\n", name, WTERMSIG(status));
} else {
fprintf(stderr, "%s fate unknown\n", name);
}
}

int main(int argc, char **argv) {
int pipefd[2];
FAILIF(pipe(pipefd), "pipe");

pid_t pid_1 = fork();
FAILIF(pid_1 < 0, "child_1: fork");
if (!pid_1) {
FAILIF(dup2(pipefd[1], 1) == -1, "child_1: dup2");
FAILIF(close(pipefd[0]), "child_1: close pipefd");
execlp("yes", "yes", "abracadabra", NULL);
FAILIF(1, "child_1: execlp");
}

pid_t pid_2 = fork();
FAILIF(pid_2 < 0, "child_2: fork");
if (!pid_2) {
FAILIF(dup2(pipefd[0], 0) == -1, "child_2: dup2");
FAILIF(close(pipefd[1]), "child_2: close pipefd");
execlp("head", "head", "-1", NULL);
FAILIF(1, "child_2: execlp");
}

FAILIF(close(pipefd[0]), "close pipefd[0]");
FAILIF(close(pipefd[1]), "close pipefd[1]");

int status_1;
int status_2;
FAILIF(waitpid(pid_1, &status_1, 0) == -1, "waitpid(child_1)");
FAILIF(waitpid(pid_2, &status_2, 0) == -1, "waitpid(child_2)");
describe_child("child_1", status_1);
describe_child("child_2", status_2);

return 0;
}

保存到 test.c 并使用 make test && ./test 运行:

abracadabra
child_1 signalled 13
child_2 exited 0

最佳答案

使用Option::take:

let pipe = child_1.stdout.take().unwrap();

let child_2 = process::Command::new("head")
.args(&["-n", "1"])
.stdin(pipe)
.stdout(process::Stdio::piped())
.spawn()?;

let output = child_2.wait_with_output()?;
child_1.wait()?;

另见:

关于process - 我如何等待标准输出已通过管道传输到另一个的 Rust `Child` 进程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56153020/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com