std::process,从缓冲区中读取标准输入和标准输出



我有一个命令cmd和三个Vec<u8>:buff1,buff2buff3。我想执行cmd,使用buff1作为stdin,并将stdout捕获为buff2stderr捕获为buff3。我希望在不显式地编写任何临时文件的情况下完成所有这些。

std::process似乎允许所有这些事情,只是不是同时发生。

如果我使用Command::new(cmd).output(),它将返回stdoutstderr的缓冲区,但没有办法给它stdin

如果我使用Command::new(cmd).stdin(Stdio::piped()).spawn()然后我可以child.stdin.as_mut().unwrap().write_all(buff1)但是我不能捕获stdoutstderr

据我所知,没有办法调用Command::new(cmd).stdout(XXX)来显式地告诉它在缓冲区中捕获stdout,默认情况下.output()是这样做的。

看起来像这样的事情应该是可能的:

Command::new(cmd)
.stdin(buff1)
.stdout(buff2)
.stderr(buff3)
.output()

由于Rust使Vec<u8>看起来像File,但Vec不实现Into<Stdio>

我错过了什么吗?是否有办法做到这一点,或者我需要读取和写入实际的文件?

如果您同意使用外部库,subprocesscrate支持以下用例:

let (buff2, buff3) = subprocess::Exec::cmd(cmd)
.stdin(buff1)
.communicate()?
.read()?;

std::process::Command做这个比看起来更棘手,因为操作系统不容易将内存区域连接到子进程的stdin。连接文件或任何类似文件的东西很容易,但是要将一块内存提供给子进程,基本上必须在循环中执行write()。虽然Vec<u8>确实实现了std::io::Read,但你不能用它来构造一个实际的File(或任何其他包含文件描述符/句柄的东西)。

将数据馈送到子进程,同时读取其输出有时被称为通信,参考2004年Python 2.4的新subprocess模块引入的Python方法。您可以使用std::process自己实现它,但是您需要小心避免死锁,以防在您尝试为命令提供输入时命令生成输出。(例如,向子进程提供一大块数据,然后读取其标准输出和标准错误的幼稚循环将容易发生此类死锁。)文档描述了一种仅使用标准库安全实现它的可能方法。

如果您希望使用缓冲区进行读写,则需要使用管道形式。原因是,至少在Unix上,进程的输入和输出是通过文件描述符完成的。由于缓冲区本质上不能转换为文件描述符,因此需要使用管道并增量地读取和写入。Rust为缓冲区提供抽象的事实并不能让你避免操作系统没有提供的事实,Rust也不会为你抽象这个。

然而,由于您将使用管道进行读写,因此您需要使用select之类的东西以避免死锁。否则,当子进程因为需要从标准输出中读取数据而不接受新输入时,您可能会尝试写入。使用selectpoll(或类似的)允许您确定每个文件描述符何时准备好被读取或写入。在Rust中,这些函数在libccrate中;我不相信Rust本身提供了这些功能。Windows将有一些类似的功能,但我不知道它是什么。

应该注意的是,除非您确定子进程的输出可以装入内存,否则以更渐进的方式处理它可能会更好。因为你将使用select,这应该不会太难。

相关内容

  • 没有找到相关文章

最新更新