[英]std::process, with stdin and stdout from buffers
I have a command cmd
and three Vec<u8>
: buff1
, buff2
, and buff3
.我有一个命令
cmd
和三个Vec<u8>
: buff1
、 buff2
和buff3
。 I want to execute cmd
, using buff1
as stdin
, and capturing stdout
into buff2
and stderr
into buff3
.我想执行
cmd
,使用buff1
作为stdin
,并将stdout
捕获到buff2
和stderr
到buff3
。 And I'd like to do all this without explicitly writing any temporary files.我想在不明确写入任何临时文件的情况下完成所有这些。
std::process
seems to allow all of those things, just not all at the same time. std::process
似乎允许所有这些事情,只是不能同时进行。
If I use Command::new(cmd).output()
it will return the buffers for stdout
and stderr
, but there's no way to give it stdin
.如果我使用
Command::new(cmd).output()
它将返回stdout
和stderr
的缓冲区,但没有办法给它stdin
。
If I use Command::new(cmd).stdin(Stdio::piped()).spawn()
then I can child.stdin.as_mut().unwrap().write_all(buff1)
but I can't capture stdout
and stderr
.如果我使用
Command::new(cmd).stdin(Stdio::piped()).spawn()
那么我可以child.stdin.as_mut().unwrap().write_all(buff1)
但我无法捕获stdout
和stderr
。
As far as I can tell, there's no way to call Command::new(cmd).stdout(XXX)
to explicitly tell it to capture stdout
in a buffer, the way it does by default with .output()
.据我所知,没有办法调用
Command::new(cmd).stdout(XXX)
来明确告诉它在缓冲区中捕获stdout
,默认情况下它使用.output()
。
It seems like something like this should be possible:看起来像这样的事情应该是可能的:
Command::new(cmd)
.stdin(buff1)
.stdout(buff2)
.stderr(buff3)
.output()
Since Rust makes a Vec<u8>
look like a File
, but Vec
doesn't implement Into<Stdio>
由于 Rust 使
Vec<u8>
看起来像File
,但Vec
没有实现Into<Stdio>
Am I missing something?我错过了什么吗? Is there a way to do this, or do I need to read and write with actual files?
有没有办法做到这一点,或者我是否需要使用实际文件进行读写?
If you're ok with using an external crate, the subprocess
crate supports this use case:如果您可以使用外部板条箱,则
subprocess
板条箱支持此用例:
let (buff2, buff3) = subprocess::Exec::cmd(cmd)
.stdin(buff1)
.communicate()?
.read()?;
Doing this with std::process::Command
is trickier than it seems because the OS doesn't make it easy to connect a region of memory to a subprocess's stdin.使用
std::process::Command
执行此操作比看起来更棘手,因为操作系统不容易将内存区域连接到子std::process::Command
的 stdin。 It's easy to connect a file or anything file-like, but to feed a chunk of memory to a subprocess, you basically have to write()
in a loop.连接文件或任何类似文件的东西很容易,但是要将一块内存提供给子进程,您基本上必须在循环中
write()
。 While Vec<u8>
does implement std::io::Read
, you can't use it to construct an actual File
(or anything else that contains a file descriptor/handle).虽然
Vec<u8>
确实实现了std::io::Read
,但您不能使用它来构造实际的File
(或任何其他包含文件描述符/句柄的东西)。 So you need to feed the data into the subprocess manually, and at the same time you need to drain its stdout and stderr, being careful to avoid a deadlock.所以你需要手动将数据输入到子进程中,同时你需要排空它的stdout和stderr,小心避免死锁。 The documentation describes a possible way of doing it using just the standard library.
该文档描述了一种仅使用标准库进行操作的可能方法。
If you want to read and write with buffers, you need to use the piped forms.如果要使用缓冲区进行读写,则需要使用管道形式。 The reason is that, at least on Unix, input and output to a process are done through file descriptors.
原因是,至少在 Unix 上,进程的输入和输出是通过文件描述符完成的。 Since a buffer cannot intrinsically be turned into a file descriptor, it's required to use a pipe and both read and write incrementally.
由于缓冲区本质上不能转换为文件描述符,因此需要使用管道并增量读取和写入。 The fact that Rust provides an abstraction for buffers doesn't allow you to avoid the fact that the operating system doesn't, and Rust doesn't abstract this for you.
Rust 为缓冲区提供抽象这一事实不允许您避免操作系统不提供的事实,并且 Rust 不会为您抽象这一事实。
However, since you'll be using pipes for both reading and writing, you'll need to use something like select
so you don't deadlock.但是,由于您将使用管道进行读取和写入,因此您需要使用诸如
select
之类的东西,以免死锁。 Otherwise, you could end up trying to write when your subprocess was not accepting new input because it needed data to be read from its standard output.否则,当您的子进程不接受新输入时,您最终可能会尝试写入,因为它需要从其标准输出中读取数据。 Using
select
or poll
(or similar) permits you to determine when each of those file descriptors are ready to be read or written to.使用
select
或poll
(或类似的)允许您确定每个文件描述符何时准备好被读取或写入。 In Rust, these functions are in the libc
crate;在 Rust 中,这些函数在
libc
crate 中; I don't believe that Rust provides them natively.我不相信 Rust 本身就提供它们。 Windows will have some similar functionality, but I have no clue what it is.
Windows 会有一些类似的功能,但我不知道它是什么。
It should be noted that unless you are certain that the subprocess's output can fit into memory, it may be better to process it in a more incremental way.应该注意的是,除非您确定子进程的输出可以放入内存,否则最好以更增量的方式处理它。 Since you're going to be using
select
, that shouldn't be too difficult.由于您将使用
select
,这应该不会太难。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.