简体   繁体   English

std::process,来自缓冲区的 stdin 和 stdout

[英]std::process, with stdin and stdout from buffers

I have a command cmd and three Vec<u8> : buff1 , buff2 , and buff3 .我有一个命令cmd和三个Vec<u8>buff1buff2buff3 I want to execute cmd , using buff1 as stdin , and capturing stdout into buff2 and stderr into buff3 .我想执行cmd ,使用buff1作为stdin ,并将stdout捕获到buff2stderrbuff3 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()它将返回stdoutstderr的缓冲区,但没有办法给它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)但我无法捕获stdoutstderr

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.使用selectpoll (或类似的)允许您确定每个文件描述符何时准备好被读取或写入。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM